虚拟内存过量提交策略
虚拟内存过量提交,是指所有进程提交的虚拟内存的总和超过物理内存的容量,内存管理子系统支持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 }
1-允许过量提交的策略
- 第5行代码,如果使用总是允许过量提交的策略,那么允许创建新的内存映射。
- 第8行代码,如果使用猜测的过量提交策略,那么估算可用内存的数量,处理如下。
- 1)第9行和第10行代码,空闲页加上文件页,文件页有后备存储设备支持,可以回收。
- 2)第12行代码,共享内存页不应该算作空闲页,它们不能被释放,只能换出到交换区。
- 3)第14行代码,加上交换区的空闲页数。
- 4)第16行代码,加上可回收的内存缓存页。使用SLAB_RECLAIM_ACCOUNT标志创建的内存缓存,宣称可回收,dentry和inode缓存应该属于这种情况。
- 5)第21行代码,减去保留的页数。
- 6)第23行和第24行代码,如果进程没有系统管理权限,那么减去为根用户保留的页数。
- 7)第26行和第27行代码,如果可用内存的页数大于申请的页数,那么允许创建新的内存映射。
2-不允许过量提交的策略
如果使用不允许过量提交的策略,那么处理如下。
- 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,那么允许创建新的内存映射。
内容来自前辈书籍:《Linux内核深度解析》