http://www.perfgeeks.com/?p=723 http://www.perfgeeks.com/?p=770
經常使用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 瞭解某個進程記憶體空間都分布,比如:
#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段中的資料很短暫,函數退出立即被銷毀。
我們使用幾個樣本小程式,加深理解
/* @filename: example-2.c */
#include <stdio.h>
int main(int argc, char *argv[])
{
char arr[] = "hello world"; /* Stack段,rw--- */
char *p = "hello world"; /* Text段,字串直接量, r-x-- */
arr[1] = 'l';
*(++p) = 'l'; /* 出錯了,Text段不能write */
return 0;
}
PS:變數p,它在Stack段,但它所指的”hello world”是一個字串直接量,放在Text段。
/* @filename:example_2_2.c */
#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;