Linux 内存管理的水位控制

系统 Linux
在讲分区页框分配器分配内存的时候,进入伙伴算法前用函数zone_watermark_fast(),来根据水位来判断当前内存情况。内存够的话采用伙伴算法分配,不够的话通过 node_reclaim 回收内存。

[[401801]]

本文转载自微信公众号「人人都是极客」,作者布道师Peter 。转载本文请联系人人都是极客公众号。

分区页框分配器之水位

在讲分区页框分配器分配内存的时候,进入伙伴算法前用函数zone_watermark_fast(),来根据水位来判断当前内存情况。内存够的话采用伙伴算法分配,不够的话通过 node_reclaim 回收内存。

水位的初始化

先看下水位的初始化:

int __meminit init_per_zone_wmark_min(void) 

        unsigned long lowmem_kbytes; 
        int new_min_free_kbytes; 
 
        lowmem_kbytes = nr_free_buffer_pages() * (PAGE_SIZE >> 10);      ------ (1)   
        new_min_free_kbytes = int_sqrt(lowmem_kbytes * 16); 
 
        if (new_min_free_kbytes > user_min_free_kbytes) { 
                min_free_kbytes = new_min_free_kbytes;                   ------ (2) 
                if (min_free_kbytes < 128) 
                        min_free_kbytes = 128; 
                if (min_free_kbytes > 65536) 
                        min_free_kbytes = 65536; 
        } else { 
                pr_warn("min_free_kbytes is not updated to %d because user defined value %d is preferred\n"
                                new_min_free_kbytes, user_min_free_kbytes); 
        } 
        setup_per_zone_wmarks();                                         ------ (3) 
        refresh_zone_stat_thresholds(); 
        setup_per_zone_lowmem_reserve();                                 ------ (4) 
 
#ifdef CONFIG_NUMA 
        setup_min_unmapped_ratio(); 
        setup_min_slab_ratio(); 
#endif 
 
        return 0; 

core_initcall(init_per_zone_wmark_min) 
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.

(1). nr_free_buffer_pages 是获取ZONE_DMA和ZONE_NORMAL区中高于high水位的总页数nr_free_buffer_pages = managed_pages - high_pages

(2). min_free_kbytes 是总的min大小,min_free_kbytes = 4 * sqrt(lowmem_kbytes)

(3). setup_per_zone_wmarks 根据总的min值,再加上各个zone在总内存中的占比,然后通过do_div就计算出他们各自的min值,进而计算出各个zone的水位大小。min,low,high的关系:low = min *125%,high = min * 150%。min,low,high之间的比例关系与 watermark_scale_factor 相关。可以通过 /proc/sys/vm/watermark_scale_factor 设置

(4). setup_per_zone_lowmem_reserve 设置每个zone的lowmem_reserve大小。lowmem_reserve值可以通过 /proc/sys/vm/lowmem_reserve_ratio 来修改。

为什么需要设置每个zone的保留内存呢,lowmem_reserve的作用是什么?

我们知道内核在分配内存时,会按照 HIGHMEM->NORMAL->DMA 的方向进行遍历,如果当前Zone分配失败,就会尝试下一个低级的Zone。我们可以想像应用进程通过内存映射申请 HIGHMEM,如果此时HIGHMEM Zone无法满足分配,则会尝试从 NORMAL 进行分配。这就有一个问题,来自 HIGHMEM Zone 的请求可能会耗尽 NORMAL Zone 的内存,最终的结果就是 NORMAL Zone 无内存提供给内核的正常分配。

因此针对这个场景,可以通过保留内存 lowmem_reserve[NORMAL] 给 NORMAL Zone 自己使用。

同样当从NORMAL Zone失败后,会尝试从zonelist中的DMA Zone申请,通过lowmem_reserve[DMA],限制来自HIGHMEM和NORMAL的分配请求。

$ cat /proc/sys/vm/lowmem_reserve_ratio 
256     32      
  • 1.
  • 2.
$ cat /proc/zoneinfo 
Node 0, zone    DMA32 
    ...... 
    pages free     361678 
        min      674 
        low      2874 
        high     3314 
        spanned  523776 
        present  496128 
        managed  440432 
        protection: (0, 3998, 3998) 
    ...... 
Node 0, zone   Normal 
    pages free     706981 
        min      1568 
        low      6681 
        high     7704 
        spanned  8912896 
        present  1048576 
        managed  1023570 
        protection: (0, 0, 0) 
    ...... 
Node 0, zone  Movable 
  pages free     0 
        min      0 
        low      0 
        high     0 
        spanned  0 
        present  0 
        managed  0 
        protection: (0, 0, 0) 
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • spanned:表示当前zone所包含的所有的pages
  • present:表示当前zone在去掉第一阶段kernel reserve的内存之后剩下的pages
  • managed:表示当前zone去掉初始化完成以后所有的kernel reserve的内存剩下的pages

结合上面arm64平台的数值举个例子,假设这2个Zones分别包含440432, 1023570个pages(实际是/proc/zoneinfo里字段managed的值)。如下图所示,使用每个区域的 managed pages 和 lowmem_reserve_ratio 计算每个区域的lowmem_reserve值,可以看出结果和protection值一样。

水位的判断

从这张图可以看出:

 

  • 如果空闲页数目min值,则该zone非常缺页,页面回收压力很大,应用程序写内存操作就会被阻塞,直接在应用程序的进程上下文中进行回收,即direct reclaim。
  • 如果空闲页数目小于low值,kswapd线程将被唤醒。默认情况下,low值为min值的125%,可以通过修改watermark_scale_factor来改变比例值
  • 如果空闲页面的值大于high值,kswapd线程将睡眠。默认情况下,high值为min值的150%,可以通过修改watermark_scale_factor来改变比例值

 

责任编辑:武晓燕 来源: 人人都是极客
相关推荐

2013-10-11 17:32:18

Linux运维内存管理

2009-12-25 15:24:16

内存管理

2021-03-17 21:34:44

Linux内存管理

2020-07-28 08:10:33

Linux内存虚拟

2023-10-18 13:31:00

Linux内存

2009-10-20 16:35:26

Linux内存管理

2017-05-18 16:30:29

Linux内存管理

2022-08-08 08:31:00

Linux内存管理

2013-09-29 15:11:46

Linux运维内存管理

2013-10-12 13:01:51

Linux运维内存管理

2009-08-17 08:32:56

Linux操作系统内存管理Linux

2023-07-06 00:45:05

Linux保护模式

2018-08-09 16:32:49

内存管理框架

2009-12-25 17:15:03

Linux内存

2020-04-08 09:20:25

Linux内存系统

2024-05-06 08:09:10

Linux内存管理

2020-06-28 09:30:37

Linux内存操作系统

2022-02-11 07:45:10

Linuxsmem系统

2013-10-12 11:15:09

Linux运维内存管理

2025-01-06 08:00:09

点赞
收藏

51CTO技术栈公众号