原文出处: PerfGeeks
经常使用top命令了解进程信息,其中包括内存方面的信息。命令top帮助文档是这么解释各个字段的。 VIRT , Virtual Image (kb) RES, Resident size (kb) SHR, Shared Mem size (kb) %MEM, Memory usage(kb) SWAP, Swapped size (kb) CODE, Code size (kb) DATA, Data+Stack size (kb) nFLT, Page Fault count nDRT, Dirty Pages count 尽管有注释,但依然感觉有些晦涩,不知所指何意? 进程内存空间 正在运行的程序,叫进程。每个进程都有完全属于自己的,独立的,不被干扰的内存空间。此空间,被分成几个段(Segment),分别是Text, Data, BSS, Heap, Stack。用户进程内存空间,也是系统内核分配给该进程的VM(虚拟内存),但并不表示这个进程占用了这么多的RAM(物理内存)。这个空间有多大?命令top输出的VIRT值告诉了我们各个进程内存空间的大小(进程内存空间随着程序的执行会增大或者缩小)。你还可以通过/proc//maps,或者pmap –d 了解某个进程内存空间都分布,比如: 1 2 3 4 5 6 7 8 9 10 11 | #cat /proc/ 1449 /maps
…
0012e000-002a4000 r-xp 00000000 08 : 07 3539877 /lib/i386-linux-gnu/libc- 2.13 .so
002a4000-002a6000 r--p 00176000 08 : 07 3539877 /lib/i386-linux-gnu/libc- 2.13 .so
002a6000-002a7000 rw-p 00178000 08 : 07 3539877 /lib/i386-linux-gnu/libc- 2.13 .so
002a7000-002aa000 rw-p 00000000 00 : 00 0
…
08048000 -0875b000 r-xp 00000000 08 : 07 4072287 /usr/local/mysql/libexec/mysqld
0875b000-0875d000 r--p 00712000 08 : 07 4072287 /usr/local/mysql/libexec/mysqld
0875d000-087aa000 rw-p 00714000 08 : 07 4072287 /usr/local/mysql/libexec/mysqld
…
|
PS:线性地址,访问权限, offset, 设备号,inode,映射文件

VM分配与释放“内存总是被进程占用”,这句话换过来可以这么理解:进程总是需要内存。当fork()或者exec()一个进程的时候,系统内核就会分配一定量的VM给进程,作为进程的内存空间,大小由BSS段,Data段的已定义的全局变量、静态变量、Text段中的字符直接量、程序本身的内存映像等,还有Stack段的局部变量决定。当然,还可以通过malloc()等函数动态分配内存,向上扩大heap。 动态分配与静态分配,二者最大的区别在于:1. 直到Run-Time的时候,执行动态分配,而在compile-time的时候,就已经决定好了分配多少Text+Data+BSS+Stack。2.通过malloc()动态分配的内存,需要程序员手工调用free()释放内存,否则容易导致内存泄露,而静态分配的内存则在进程执行结束后系统释放(Text, Data), 但Stack段中的数据很短暂,函数退出立即被销毁。 我们使用几个示例小程序,加深理解 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 | # include <stdio.h>
int main( int argc, char *argv[])
{
char arr[] = "hello world" ;
char *p = "hello world" ;
arr[ 1 ] = 'l' ;
*(++p) = 'l' ;
return 0 ;
}
PS:变量p,它在Stack段,但它所指的”hello world”是一个字符串直接量,放在Text段。
# include <stdio.h>
# include <stdlib.h>
# include <string.h>
char *get_str_1()
{
char str[] = "hello world" ;
return str;
}
char *get_str_2()
{
char *str = "hello world" ;
return str;
}
char *get_str_3()
{
char tmp[] = "hello world" ;
char *str;
str = (char *)malloc( 12 * sizeof(char));
memcpy(str, tmp, 12 );
return str;
}
int main( int argc, char *argv[])
{
char *str_1 = get_str_1();
char *str_2 = get_str_2();
char *str_3 = get_str_3();
printf( "%s\n" , str_1);
printf( "%s\n" , str_2);
printf( "%s\n" , str_3);
if (str_3 != NULL)
{
free(str_3);
str_3 = NULL;
}
return 0 ;
}
PS:函数get_str_1()返回Stack段数据,编译时会报错。Heap中的数据,如果不用了,应该尽早释放free()。
# include <stdio.h>
# include <stdlib.h>
# include <string.h>
# include <unistd.h>
char data_ var = '1' ;
char *mem_killer()
{
char *p;
p = (char *)malloc( 1024 * 1024 * 4 );
memset(p, '\0' , 1024 * 1024 * 4 );
p = &data_ var ;
return p;
}
int main( int argc, char *argv[])
{
char *p;
for (;;)
{
p = mem_killer();
printf( "%c\n" , *p);
sleep( 20 );
}
return 0 ;
}
|
PS:使用malloc(),特别要留意heap段中的内存不用时,尽早手工free()。通过top输出的VIRT和RES两值来观察进程占用VM和RAM大小。 本节结束之前,介绍工具size。因为Text, BSS, Data段在编译时已经决定了进程将占用多少VM。可以通过size,知道这些信息。 # gcc example_2_3.c -o example_2_3 # size example_2_3 text data bss dec hex filename 1403 272 8 1683 693 example_2_3

|