Linux总是以Lazy的方式给应用程序分配内存

Linuxer 发表于 2018-04-27 15:10:09 收藏 已收藏
赞(0) •  评论(0

Linux总是以Lazy的方式给应用程序分配内存

Linuxer 发表于 2018-04-27 15:10:09

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。

收藏

相关话题
文章来源专栏
+关注

评论(0)

加载更多评论

参与评论

相关文章

分享到

QQ空间 QQ好友 微博
取消