3.4.4 虚拟内存过量提交策略
虚拟内存过量提交,是指所有进程提交的虚拟内存的总和超过物理内存的容量,内存管理子系统支持3种虚拟内存过量提交策略。
(1)OVERCOMMIT_GUESS(0):猜测,估算可用内存的数量,因为没法准确计算可用内存的数量,所以说是猜测。
(2)OVERCOMMIT_ALWAYS(1):总是允许过量提交。
(3)OVERCOMMIT_NEVER(2):不允许过量提交。
默认策略是猜测,用户可以通过文件“/proc/sys/vm/overcommit_memory”修改策略。
在创建新的内存映射时,调用函数__vm_enough_memory根据虚拟内存过量提交策略判断内存是否足够,主要代码如下:
mm/util.c
1 int __vm_enough_memory(struct mm_struct *mm, long pages, int cap_sys_admin)
2 {
3 long free, allowed, reserve;
4 …
5 if (sysctl_overcommit_memory == OVERCOMMIT_ALWAYS)
6 return 0;
7
8 if (sysctl_overcommit_memory == OVERCOMMIT_GUESS) {
9 free = global_page_state(NR_FREE_PAGES);
10 free += global_node_page_state(NR_FILE_PAGES);
11
12 free -= global_node_page_state(NR_SHMEM);
13
14 free += get_nr_swap_pages();
15
16 free += global_page_state(NR_SLAB_RECLAIMABLE);
17
18 if (free <= totalreserve_pages)
19 goto error;
20 else
21 free -= totalreserve_pages;
22
23 if (! cap_sys_admin)
24 free -= sysctl_admin_reserve_kbytes >> (PAGE_SHIFT - 10);
25
26 if (free > pages)
27 return 0;
28
29 goto error;
30 }
31
32 allowed = vm_commit_limit();
33
34 if (! cap_sys_admin)
35 allowed -= sysctl_admin_reserve_kbytes >> (PAGE_SHIFT - 10);
36
37 if (mm) {
38 reserve = sysctl_user_reserve_kbytes >> (PAGE_SHIFT - 10);
39 allowed -= min_t(long, mm->total_vm / 32, reserve);
40 }
41
42 if (percpu_counter_read_positive(&vm_committed_as) < allowed)
43 return 0;
44 error:
45 vm_unacct_memory(pages);
46
47 return -ENOMEM;
48 }
第5行代码,如果使用总是允许过量提交的策略,那么允许创建新的内存映射。
第8行代码,如果使用猜测的过量提交策略,那么估算可用内存的数量,处理如下。
1)第9行和第10行代码,空闲页加上文件页,文件页有后备存储设备支持,可以回收。
2)第12行代码,共享内存页不应该算作空闲页,它们不能被释放,只能换出到交换区。
3)第14行代码,加上交换区的空闲页数。
4)第16行代码,加上可回收的内存缓存页。使用SLAB_RECLAIM_ACCOUNT标志创建的内存缓存,宣称可回收,dentry和inode缓存应该属于这种情况。
5)第21行代码,减去保留的页数。
6)第23行和第24行代码,如果进程没有系统管理权限,那么减去为根用户保留的页数。
7)第26行和第27行代码,如果可用内存的页数大于申请的页数,那么允许创建新的内存映射。
如果使用不允许过量提交的策略,那么处理如下。
1)第32行代码,计算提交内存的上限。有两个控制参数:sysctl_overcommit_kbytes是字节数,sysctl_overcommit_ratio是比例值,sysctl_overcommit_kbytes的默认值是0, sysctl_overcommit_ratio的默认值是50。如果sysctl_overcommit_kbytes不是0,那么上限等于“sysctl_overcommit_kbytes + 交换区的空闲页数”,否则上限等于“(物理内存容量 − 巨型页总数)* sysctl_overcommit_ratio/100 + 交换区的空闲页数”。
2)第34行和第35行代码,如果进程没有系统管理权限,那么需要为根用户保留一部分内存。
3)第37~40行代码,为了防止一个用户启动一个消耗内存大的进程,保留一部分内存:取“进程虚拟内存长度的1/32”和“用户保留的页数”的较小值。
4)第42行和第43行代码,vm_committed_as是所有进程提交的虚拟内存的总和,如果它小于allowed,那么允许创建新的内存映射。