最近在看一本书,《嵌入式Linux内存使用与性能优化》,这本书重点关注的是Linux内存的使用与优化策略,相关基础知识讲得比较通俗易懂,优化策略也阐述得详略得当,感觉挺不错的。我就其第一章的关于Linux内存管理的一些基础知识做了一些笔记,分享在此,如果想深入了解Linux内存管理的细节以及内存使用优化策略,建议大家也去买本看看吧。


1.  怎样查看系统当前可用内存 ?

答:使用 free 命令即可。如下图所示:

 

说明:


buffers: 主要用来给Linux系统中块设备做缓冲区(把分散的写操作集中进行,减少对磁盘或者Flash设备的写次数,提高系统性能)

cached:用来缓冲打开的文件(把从磁盘或者Flash中读取的数据保存在内存中,若再次读取该块时,则直接从内存中读取而不需要再访问磁盘或者Flash设备)

在系统中内存是很宝贵的资源,故Linux在内存使用上的宗旨是:如果内存充足,不用白不用,尽量使用内存来缓存一些文件,从而加快进程的运行速度;而当内存不足的时候,这些内存又会被回收,供程序使用。

所以,当前系统真正空闲可以使用的内存为:free+buffers+cached (KB)

 

2.  free命令得到的数据是哪里来的?

 

答: 来自 /proc 虚拟文件系统,我们可以通过 /proc/meminfo文件来了解当前系统的内存使用情况,如下图所示:



从上面可以看出,系统一共有 2050600KB的物理内存,当前系统可用的物理内存为: Memfree+Buffers+Cached

 

3.  操作系统的虚拟内存与物理内存机制

 

操作系统为程序员屏蔽了物理内存的使用,在32位操作系统中,每个进程面对的都是4GB的内存空间,称为虚拟内存。操作系统采用了延迟分配物理内存的策略,针对进程的内存分配请求,它只是在内核中分配了一段虚拟地址,只有当确实使用这块内存时,系统才会为其分配物理地址。

 

我们来看一下下面这段代码: 

 

#include <stdio.h> #include <stdlib.h> #include <string.h>  int main() {     char * p = (char *)malloc(10);      char * q = (char *)malloc(200);      strcpy(p,"123");      return 0;  }

问题一:该代码执行时,内存的分配过程是怎样的?

 

(1)  char * p= (char *)malloc(10);

 

   char *q =  (char *)malloc(200);

 

这2句,系统只给该进程分配了虚拟内存,而并没有分配物理内存。

 

(2)  strcpy(p,"123");

 

这一句,由于进程需要真正使用这块内存了,因此系统会产生一个页故障,从而为该进程分配一个物理页面。

 

(3)  整个程序最终只是为 p 分配的物理内存,而只是给 q 分配了虚拟内存。

 

问题二: 该代码实际分配的内存究竟多大?

 

系统给该进程分配的虚拟内存为 : 10B + 200B = 210 Byte

 

给该进程分配的物理内存为 4KB,因为系统规定,分配物理内存的最小单位为一个物理页面,一般是4KB

 

注:用户态申请内存是以Byte为单位,而内核态申请内存是以页面(4KB)为单位

 

4.  Linux的内存回收机制

 

在Linux系统中,有一个专门的守护进程 kswapd,它会定期地检查系统中空闲内存的数量,一旦发现空闲内存数量小于一个阈值的时候,就会将若干页面换出,存放到交换分区中,以腾出足够的内存空间。

 

对于交换分区的使用,有着如下的规则:

 

对于那些没有被改写过的页面,这块内存不需要写到交换分区上,可以直接回收。


对于那些已经改写的页面,我们称之为脏页面(dirty page),则需要写到交换分区。

 

但在使用Flash作为存储介质的嵌入式设备中,一般没有交换分区,因此对于dirty page,只能保留在系统中,无法换出。原因如下:

 

(1) 一旦使用了交换分区,系统的性能会下降很快,不可接受

 

(2) Flash的写次数是有限的,大概在几十万次,如果在Flash上面建立交换分区的话,必然导致对Flash的频繁读写,进而影响Flash的寿命。


下面分析下,一个进程中,哪些内存可能是 dirty page 页面,哪些不是?


(1) 代码段,其权限是只读属性,不可能被改写,所以其所占的物理内存,都不是 dirty page

 

(2) 数据段,其权限是可读、可写,所以其所占的物理内存可能是 dirty page,也可能不是

 

(3) 堆栈段,其没有对应的映射文件,内容都是通过程序来改写的,所以其所占的物理内存全部是 dirty page

 

(4) 共享内存,其所占的物理内存,全部是 dirty page


综上所述,也就是说, 可以直接被回收的内存,主要是进程的代码段和未修改的数据段。

 

5.  为什么在 malloc时,要求输入申请的空间大小,而在 free 时,不需要输入释放的空间大小?

 

    因为程序调用 malloc 函数申请内存时,并不是直接向操作系统申请,而是先由 glibc 的内存管器模块接收请求,它再通过系统调用向内核申请一块内存并将地址p返回给用户,同时,在 p-4 这个地址记录下 malloc 空间的大小,glibc 在 free 这块内存的时候,通过 p-4 即可知道需要释放的内存大小是多少。