Linux内存分配有其特殊性,理解其分配机制,将有助于调试程序,特别是和内存泄露相关的问题分析,本文件试图以示例的方式简单的讲解一下Linux内存分配机制,希望对你的工作有所帮助。
先粘贴出示例将使用的源代码,为了方便讲解,为每行加上行号,如下:
1) #include
2) #include
3) #include
4)
5) int main()
6) {
7) const size_t st = 1024*1024; // 1M大小
8) const size_t ss = 1*1024*1024*1000; // 1G大小
9) char* p = new char[ss];
10) for (size_t i=0; i
11) getchar(); // 停顿一下,是为了方便观察内存的变化,下同
12) memset(p, 0, st);
13) p += st;
14) }
15) char* p2 = new char[ss];
16) getchar();
17) memset(p2, 0, ss);
18) getchar();
19) return 0;
20) }
要想比较透彻地了解Linux内存分配机制,还需要明白top或free命令中的几个属性:
l VIRT:进程使用的虚拟内存总量,单位kb。VIRT=SWAP+RES
l SWAP:进程使用的虚拟内存中,被换出的大小,单位kb
l RES:进程使用的、未被换出的物理内存大小(即当前实际占用的物理内存),单位kb。RES=CODE+DATA
另外,free命令还包括“-/+ buffers/cache”两个属性,前者(-buffers/cache)表示实际被占用的物理内存数,而后者(+buffers/cache)表示可以被应用程序使用的内存总数。
这几个属性和程序中的内存分配(malloc/new)之间有什么关系了?
malloc分配的内存反映的是VIRT的变化,所以如果VIRT值一直在不停的往上增涨,则说明程序中存在内存泄露,否则表示程序不存在泄露。
而通过大家只关注了RES值,当RES值不断的往上涨时,就认识程序存在内存泄露,其实这是不正确的,只要VIRT值没有增涨,那么即使RES值在增涨,也不代表内存泄露,只有VIRT值在不停地增涨,才能表示程序存在内存泄露,这点将通过上面的示例程序来说明。
在现代操作系统中,进程可使用的均是虚拟的地址空间,程序并不直接和物理内存打交道,对一个32位程序,理论上其可用内存最大为4G,这通常是比物理内存
大。只有当malloc出来的进程被实在的使用后,才会表现在RES上,RES表示的是实实在在的有多少物理内存被应用程序占用了。
当示例程序第一次运行到第11行时,使用ps
aux命令查看该进程的内存使用量时,可以发现其VIRT对应的值为1G多,而VSS值通常远远小于它,然后按Enter回车键,让它执行完第12行,这
个时候再使用ps aux查看它的内存占用情况,可以发现VIRT值保持不变,但VSS值增加了1M大小。
当程序运行到第16行时,我们可以发现,其VIRT值也增大了。
另外,Linux内存分配采用了贪婪的算法,它总是优先从“从未动用过的内存(对应top命令中的free值)”里取出一块内存供程序使用,只有当从这里
取不到需要的内存时,才会根据淘汰算法,从cache里面拿出一块内存,这也可以通过非常简单的实验来展现这个现象,写一个非常简单的程序,程序运行时分
配一块大于free值而小于cached值的内存,运行结束之后,会发现free值变大了,而cached变小了,内存就这样被强制从cached中解放
出来了,但在实际中不建议这样操作,因为cached的目的就是为了提高性能。
阅读(1834) | 评论(0) | 转发(0) |