首先说明,本文讨论的cache指的是Linux中的page cache,buffer指的是buffer cache,也即cat /proc/meminfo中显示的cache和buffer。
我们知道,Linux下频繁存取文件或单个大文件时物理内存会很快被用光,当程序结束后内存不会被正常释放而是一直作为cahce占着内存。因此系统经常会因为这点导致OOM产生,尤其在等大压力场景下概率较高,此时,第一时间查看cache和buffer内存是非常高的。此类问题目前尚未有一个很好的解决方案,以往遇到大多会做规避处理,因此本案尝试给出一个分析和解决的思路。
解决该问题的关键是理解什么是cache和buffer,什么时候消耗在哪里以及如何控制cache和buffer,所以本问主要围绕这几点展开。整个讨论过程尽量先从内核源码分析入手,然后提炼APP相关接口并进行实际操作验证,最后总结给出应用程序的编程建议。
可以通过free或者cat /proc/meminfo查看到系统的buffer和cache情况
1.1 Cache和Buffer分析
从cat /proc/meminfo入手,先看看该接口的实现:
static int meminfo_proc_show(struct seq_file *m, void *v){……cached = global_page_state(NR_FILE_PAGES) - total_swapcache_pages() - i.bufferram;if (cached < 0) cached = 0;…… seq_printf(m, "MemTotal: %8lu kB" "MemFree: %8lu kB" "Buffers: %8lu kB" "Cached: %8lu kB" …… , K(i.totalram), K(i.freeram), K(i.bufferram), K(cached), …… );……}
其中,内核中以页框为单位,通过宏K转化成以KB为单位输出。这些值是通过si_meminfo来获取的:
void si_meminfo(struct sysinfo *val){ val->totalram = totalram_pages; val->sharedram = 0; val->freeram = global_page_state(NR_FREE_PAGES); val->bufferram = nr_blockdev_pages(); val->totalhigh = totalhigh_pages; val->freehigh = nr_free_highpages(); val->mem_unit = PAGE_SIZE;}
其中bufferram来自于nr_blockdev_pages(),该函数计算块设备使用的页框数,遍历所有块设备,将使用的页框数相加。而不包含普通文件使用的页框数。
long nr_blockdev_pages(void){ struct block_device *bdev; long ret = 0; spin_lock(&bdev_lock); list_for_each_entry(bdev, &all_bdevs, bd_list) { ret += bdev->bd_inode->i_mapping->nrpages; } spin_unlock(&bdev_lock); return ret;}