前序文章:
郝健: Linux内存管理学习笔记-第1节课
郝健: Linux内存管理学习笔记-第2节课
郝健: Linux内存管理学习笔记-第3节课
摘要
page cache
free命令的详细解释
file-backed的页面和匿名页
页面回收和LRU
swap以及zRAM
0. 课前思考
Linux总是以Lazy的方式给应用程序分配内存,包括堆、栈(函数调用越深,用的栈越多,最终发生page fault才得到栈)、代码段、数据段。那么,这些已经获得到内存的段会一直占用着内存吗?
1. page cache
Linux下读写文件,主要有两种方式:
read/write
调用read读文件,Linux内核会申请一个page cache,然后把文件读到page cache中,再将内核空间的page cache拷贝到用户空间的buf。
调用write写文件,则将用户空间buf拷贝到内核空间page cache。
mmap
mmap可以避免buf从用户空间到内核空间的拷贝过程。
直接把文件映射成一个虚拟地址指针,这个指针指向内核申请的page cache。内核知道page cache与硬盘中文件的对应关系。
使用mmap读写文件
注:读写权限需要对应,否则触发page fault。
编译执行:
mmap看起来是由一个虚拟地址对应一个文件(可以直接用指针访问文件),本质上是把进程的虚拟地址空间映射到DRAM(内核从这片区域申请内存做page cache),而这个page cache对应磁盘中的某个文件,且Linux内核会维护page cache和磁盘中文件的交换关系。详见下图:
page cache可以看作内存针对磁盘的一个缓存,应用程序在写文件时,其实只是将内容写入了page cache,使用sync才能真的写入文件。
ELF可执行程序头部会记录代码段的位置,代码段的本质就将ELF文件中的代码段直接mmap映射到一个虚拟地址,且权限为R+X。
page cache可以极大的提高系统整体性能。如,进程A读一个文件,内核空间会申请page cache与此文件对应,并记录对应关系,进程B再次读同样的文件就会直接命中上一次的page cache,读写速度显著提升。但注意,page cache会根据LRU算法(最近最少使用)进行替换。
演示:page cache对程序执行时间的影响
第一次多出很多硬盘io操作;第二次python的很多环境都在内存中命中了,速度提升显著。用\time -v命令再次对比:
附注:
i. swap:
动词:swapping,内存与磁盘的颠簸行为
名字:swap分区
ii. cache可以通过/proc/sys/vm/drop_caches强行释放,写1释放page cache,2释放dentries和inode,3释放两者。
2. free命令的详细解释
上图中,buffers与cached都是文件系统的缓存,没有本质区别,唯一区别是背景不同:
i. 当以文件系统(ext4,xfs等)的形式去访问文件系统中的文件,如mount /dev/sda1 /mnt后,/mnt目录下会有很多文件,访问这类文件所产生的cache就对应free命令显示的cached列。
ii. 直接访问/dev/sda1时,如用户程序直接打开open(“dev/sda1…)或执行dd命令,以及文件系统本身去访问裸分区,所产生的cache对应free命令显示的buffers列。
参考下图所示:
演示:读硬盘裸分区导致free命令显示内容变化
linux kernel 3.14版本以后,已经采用新的free命令,如下图:
老版本free中-/+buffers/cache的含义如下图:
新版本free中多出available,即是评估出现在还有多少内存可供应用程序使用。
3. file-backed的页面和匿名页
page cache和CPU内部cache一样,是可以被替换出去的。有文件背景的页面可以swap到磁盘。EG. 启动firefox,跑一个oom的程序,前后对比firefox的smaps文件。可以看出firefox在内存紧张的情况下,代码段、mmap的字体文件等都被替换出去而不驻留内存了。
那么,没有文件背景的匿名页是如何交换回收的呢?是否常住内存?详见下图:
有文件背景的页面和匿名页都需要swap,有文件背景的页面向自己的文件背景中交换,匿名页向swap分区和swapfile中交换。即使编译内核时将CONFIG_SWAP关闭(只是关闭了匿名页的交换),linux内核中kswapd的线程还是会swap有文件背景的页面。
Linux有三个水位:min,low,high。一旦内存达到低水位时,后台自动回收直到回收到高水位。当内存到达min水位时,直接堵住进程进行回收。
匿名页和有文件背景的页面都有可能被回收,/proc/sys/vm/swappiness值比较大时,倾向回收匿名页;swappiness值比较小时倾向回收有文件背景的页面。回收算法皆为LRU。
附注:
数据段比较特殊,在没有写的情况是有文件背景的,但被写后就变为匿名页。
Windows中的虚拟内存就相当于Linux的swapfile。
4. 页面回收和LRU
如上图,运行到第4列时,第1页最不活跃。运行到第5列时又把第1页踏了一次,此时第2页变为最不活跃的。运行到第6列时又把第2页踏了一次,此时第3页变为最不活跃的,所以在第7列时,由于要访问一个新的第5页,3就被替换出去。
5. swap以及zRAM
嵌入式系统受flash限制,很少使用swap分区,一般都swapoff。所以嵌入式系统引入zRAM技术。
zRAM直接把一块内存模拟成一个硬盘分区,当作swap分区使用,此分区自带透明压缩功能,当匿名页向zRAM分区写时,Linux内核使CPU自动对匿名页进行压缩。接下来,当应用程序又执行到刚才的匿名页时,由于此页已经被swap到zRAM中,内存中没有命中,页表也没有命中,所以此时再去访问这块内存时再次发生page fault,Linux就从zRAM分区中将匿名页透明的解压出来还到内存中。
zRAM的特点是用内存来做swap分区,透明压(两页匿名页有可能被压缩成一页),透明解(一页解压成两页),这样其实相当于扩大了内存,但会多损耗一些CPU。
内存管理报名
报名:《Linux的任督二脉》之《内存管理》微课(连续5晚)