英语

内存平衡

由 Kanoj Sarcar 于 2000 年 1 月启动 <kanoj@sgi.com>

对于 !__GFP_HIGH 和 !__GFP_KSWAPD_RECLAIM 以及非 __GFP_IO 分配,都需要内存平衡。

调用者可能避免回收的第一个原因是,由于持有自旋锁或处于中断上下文中,调用者无法休眠。第二个原因是,调用者愿意在不产生页面回收开销的情况下使分配失败。这可能会发生在具有 0 阶回退选项的机会性高阶分配请求中。在这种情况下,调用者也可能希望避免唤醒 kswapd。

发出 __GFP_IO 分配请求是为了防止文件系统死锁。

在没有不可休眠的分配请求的情况下,进行平衡似乎是有害的。页面回收可以延迟启动,即仅在需要时(又名区域空闲内存为 0)启动,而不是使其成为一个主动过程。

话虽如此,内核应该尝试从直接映射池中满足对直接映射页面的请求,而不是回退到 dma 池,以便保持 dma 池充满以满足 dma 请求(原子或非原子)。类似的论点适用于高内存和直接映射页面。另一方面,如果有很多空闲的 dma 页面,则最好通过从 dma 池分配一个来满足常规内存请求,而不是产生常规区域平衡的开销。

在 2.2 中,只有当空闲页面的_总_数低于总内存的 1/64 时,才会启动内存平衡/页面回收。通过适当的 dma 和常规内存比例,即使 dma 区域完全为空,也很有可能不会进行平衡。2.2 已经在不同内存大小的生产机器上运行,即使存在这个问题,似乎也能正常运行。在 2.3 中,由于 HIGHMEM,这个问题会加剧。

在 2.3 中,区域平衡可以通过两种方式之一完成:根据区域大小(以及可能较低类区域的大小),我们可以在初始化时决定在平衡任何区域时应瞄准多少空闲页面。好处是,在平衡时,我们不需要查看较低类区域的大小,坏处是,由于忽略较低类区域中可能较低的使用率,我们可能会进行过于频繁的平衡。此外,通过对分配例程进行细微的更改,可以将 memclass() 宏简化为简单的相等性。

另一种可能的解决方案是,仅当区域的空闲内存_以及_其所有较低类区域的空闲内存低于该区域及其较低类区域中总内存的 1/64 时,我们才进行平衡。这解决了 2.2 平衡问题,并尽可能接近 2.2 的行为。此外,平衡算法在具有不同数量和类型的区域的各种架构上以相同的方式工作。如果我们想变得花哨,我们可以在将来为不同区域中的空闲页面分配不同的权重。

请注意,如果常规区域的大小与 dma 区域相比很大,那么在决定是否平衡常规区域时,考虑空闲 dma 页面就变得不那么重要了。那么第一个解决方案就更具吸引力了。

附加的补丁实现了第二个解决方案。它还“修复”了两个问题:首先,对于不可休眠的分配,kswapd 会像在 2.2 中一样在内存不足的情况下被唤醒。其次,还平衡了 HIGHMEM 区域,以便为 replace_with_highmem() 提供获得 HIGHMEM 页面的机会,并确保 HIGHMEM 分配不会回退到常规区域。这也确保了 HIGHMEM 页面不会泄漏(例如,在 HIGHMEM 页面位于交换缓存中但没有人使用的情况下)

kswapd 还需要知道它应该平衡的区域。kswapd 主要在无法进行平衡的情况下需要,可能是因为所有分配请求都来自中断上下文,并且所有进程上下文都在休眠。对于 2.3,kswapd 实际上不需要平衡高内存区域,因为中断上下文不请求高内存页面。kswapd 查看区域结构中的 zone_wake_kswapd 字段来决定一个区域是否需要平衡。

如果窃取页面会减轻页面节点中任何低于其水印的区域的内存压力,则会从进程内存和 shm 中窃取页面。

watemark[WMARK_MIN/WMARK_LOW/WMARK_HIGH]/low_on_memory/zone_wake_kswapd:这些是每个区域的字段,用于确定区域何时需要平衡。当页面数低于 watermark[WMARK_MIN] 时,滞后字段 low_on_memory 将被设置。这将一直保持设置,直到空闲页面数变为 watermark[WMARK_HIGH]。当设置了 low_on_memory 时,页面分配请求将尝试释放该区域中的一些页面(前提是在请求中设置了 GFP_WAIT)。与此正交的是,决定是否启动 kswapd 以释放某些区域页面的决定。该决定不是基于滞后的,而是在空闲页面数低于 watermark[WMARK_LOW] 时完成的;在这种情况下,也会设置 zone_wake_kswapd。

我听说过的(好)想法

  1. 动态体验应影响平衡:可以跟踪一个区域的失败请求数并将其反馈到平衡方案中 (jalvo@mbay.net)

  2. 实现一个类似于 replace_with_highmem() 的 replace_with_regular() 来保留 dma 页面。 (lkd@tantalophile.demon.co.uk)