在Linux的"free"命令的输出结果中,有一项是"available"(对应"/proc/meminfo"中的"MemAvailable"),它是对启动一个新应用的“可使用内存”的 估算 。在一次实验中,我偶然发现了它出现的变化。
这篇文章介绍过"watermark_scale_factor",它的默认值是10,最大允许值是1000。笔者为了增加kswapd的启动次数(更积极地回收内存),就把它调到了1000,结果发现"available"这一项产生了巨大的变化,但其他几项的数据都没有任何改变:
真的是由于设置watermark的参数引起的吗?试着把它改回去:
看来还真是,但这是为什么呢?还得从"available"内存的计算方法说起,其对应的函数实现是 si_mem_available ():
long si_mem_available(void)
{
// free - ( lowmem reserve + high watermark )
available = global_zone_page_state(NR_FREE_PAGES) - totalreserve_pages;
// zone low watermark
for_each_zone(zone)
wmark_low += low_wmark_pages(zone);
// part of page cache
pagecache = pages[LRU_ACTIVE_FILE] + pages[LRU_INACTIVE_FILE];
available += pagecache - min(pagecache / 2, wmark_low);;
// other reclaimable
reclaimable = global_node_page_state(NR_SLAB_RECLAIMABLE) +
global_node_page_state(NR_KERNEL_MISC_RECLAIMABLE);
available += reclaimable - min(reclaimable / 2, wmark_low);
return available;
}
一般认为,空闲的内存一定是可用的,其实并不尽然,因为有zone watermark和lowmem reserve的存在。前者作为启动内存回收的watermark依据存在,而后者主要是为了避免被高位zone在fallback时过度挤压自己的内存而reserve。
所有zones的wmark_high值之和,加上lowmem reserve,就构成了totalreserve_pages,这部分内存虽然未被分配,但不能算在"available"的范畴里。
这就是为什么在本文开头的实验中,调整zone watermark参数会引起"available"值的变化,因为它导致"high"相对于"min"的值增大,而"min"值不变,所以"high"值增大,进而使"available"的值减小。
内存已经被分配,但经过内存回收后可以释放的部分,也属于“可用内存”。Page cache和anonymous pages中都存在可被回收的部分,但page cache由于存在后备文件,回收的时候不需要像anonymous pages那样向磁盘申请swap space空间,而且只读的page cache甚至都不用writeback,直接discard即可,所以通常优先回收file-backed的page cache。
swapping操作不光更加耗时,而且必须要有swap分区才能将anonymous pages换出,这在某些系统上是没法满足的。因此,"available"的计算并没有把anonymous pages中可回收的部分考虑进去。
但page cache中也存在一些内存是 不可回收 的(unreclaimable)的,包括:
内核自己使用的页面通常不会被回收。内核本身不需要很多的内存,而且这些内存的使用频率很高,回收内核内存增加的复杂度往往超过回收带来的益处。
被临时lock的页面,比如将页面添加到page cache或从page cache移除时,页面正在write back同步时,为了互斥,都需要通过lock_page()将页面暂时锁住。被lock的内存数量可通过"/proc/meminfo"中的"Mlocked"查看,它同时也属于"Unevictable"的LRU链表的一部分。
flag被设置为PG_reserved的页面。
但要精确统计这些不可回收的page cache比较困难,因此采用估算的方法,以page cache的一半和"wmark_low"中偏小的那个值,作为保留不被回收的page cache大小。此外,slab中的一部分内存也是可以回收的。
因此,"available"的内存主要包括了:空闲内存减去所有zones的lowmem reserve和high watermark,再加上page cache和slab中可以回收的部分。
参考:
原创文章,转载请注明出处。