Linux 内存管理的水位控制

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

[[401801]]

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

分区页框分配器之水位

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

水位的初始化

先看下水位的初始化:

  1. int __meminit init_per_zone_wmark_min(void) 
  2.         unsigned long lowmem_kbytes; 
  3.         int new_min_free_kbytes; 
  4.  
  5.         lowmem_kbytes = nr_free_buffer_pages() * (PAGE_SIZE >> 10);      ------ (1)   
  6.         new_min_free_kbytes = int_sqrt(lowmem_kbytes * 16); 
  7.  
  8.         if (new_min_free_kbytes > user_min_free_kbytes) { 
  9.                 min_free_kbytes = new_min_free_kbytes;                   ------ (2) 
  10.                 if (min_free_kbytes < 128) 
  11.                         min_free_kbytes = 128; 
  12.                 if (min_free_kbytes > 65536) 
  13.                         min_free_kbytes = 65536; 
  14.         } else { 
  15.                 pr_warn("min_free_kbytes is not updated to %d because user defined value %d is preferred\n"
  16.                                 new_min_free_kbytes, user_min_free_kbytes); 
  17.         } 
  18.         setup_per_zone_wmarks();                                         ------ (3) 
  19.         refresh_zone_stat_thresholds(); 
  20.         setup_per_zone_lowmem_reserve();                                 ------ (4) 
  21.  
  22. #ifdef CONFIG_NUMA 
  23.         setup_min_unmapped_ratio(); 
  24.         setup_min_slab_ratio(); 
  25. #endif 
  26.  
  27.         return 0; 
  28. core_initcall(init_per_zone_wmark_min) 

(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的分配请求。

  1. $ cat /proc/sys/vm/lowmem_reserve_ratio 
  2. 256     32      
  1. $ cat /proc/zoneinfo 
  2. Node 0, zone    DMA32 
  3.     ...... 
  4.     pages free     361678 
  5.         min      674 
  6.         low      2874 
  7.         high     3314 
  8.         spanned  523776 
  9.         present  496128 
  10.         managed  440432 
  11.         protection: (0, 3998, 3998) 
  12.     ...... 
  13. Node 0, zone   Normal 
  14.     pages free     706981 
  15.         min      1568 
  16.         low      6681 
  17.         high     7704 
  18.         spanned  8912896 
  19.         present  1048576 
  20.         managed  1023570 
  21.         protection: (0, 0, 0) 
  22.     ...... 
  23. Node 0, zone  Movable 
  24.   pages free     0 
  25.         min      0 
  26.         low      0 
  27.         high     0 
  28.         spanned  0 
  29.         present  0 
  30.         managed  0 
  31.         protection: (0, 0, 0) 
  • 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内存管理

2009-08-17 08:32:56

Linux操作系统内存管理Linux

2023-07-06 00:45:05

Linux保护模式

2013-10-12 13:01:51

Linux运维内存管理

2013-09-29 15:11:46

Linux运维内存管理

2018-08-09 16:32:49

内存管理框架

2020-06-28 09:30:37

Linux内存操作系统

2009-12-25 17:15:03

Linux内存

2020-04-08 09:20:25

Linux内存系统

2022-02-11 07:45:10

Linuxsmem系统

2013-10-12 11:15:09

Linux运维内存管理

2013-10-11 17:24:47

Linux运维内存管理

2013-06-20 10:25:56

点赞
收藏

51CTO技术栈公众号