linux 跟踪内存,用strace跟踪malloc内存分配
strace介紹
strace是一個非常有用的命令,它用于記錄和跟蹤程序運行期間收到的信號和調用的系統調用。
strace的簡單使用
ubuntu64:~$ strace cat /dev/null
execve("/bin/cat", ["cat", "/dev/null"], [/* 32 vars */]) = 0
brk(NULL) = 0x112e000
access("/etc/ld.so.nohwcap", F_OK) = -1 ENOENT (No such file or directory)
. . .
read(3, "", 131072) = 0
munmap(0x7f19a65be000, 139264) = 0
close(3) = 0
close(1) = 0
close(2) = 0
exit_group(0) = ?
+++ exited with 0 +++
每一行表示一個系統調用, 左邊為系統調用的名稱和參數, 右邊為系統調用返回的結果。
參數
-c 統計每一系統調用的所執行的時間,次數和出錯的次數等.
-d 輸出strace關于標準錯誤的調試信息.
-f 跟蹤由fork調用所產生的子進程.
-ff 如果提供-o filename,則所有進程的跟蹤結果輸出到相應的filename.pid中,pid是各進程的進程號.
-F 嘗試跟蹤vfork調用.在-f時,vfork不被跟蹤.
-h 輸出簡要的幫助信息.
-i 輸出系統調用的入口指針.
-q 禁止輸出關于脫離的消息.
-r 打印出相對時間關于,,每一個系統調用.
-t 在輸出中的每一行前加上時間信息.
-tt 在輸出中的每一行前加上時間信息,微秒級.
-ttt 微秒級輸出,以秒了表示時間.
-T 顯示每一調用所耗的時間.
-v 輸出所有的系統調用.一些調用關于環境變量,狀態,輸入輸出等調用由于使用頻繁,默認不輸出.
-V 輸出strace的版本信息.
-x 以十六進制形式輸出非標準字符串
-xx 所有字符串以十六進制形式輸出.
-a column
設置返回值的輸出位置.默認 為40.
-e expr
指定一個表達式,用來控制如何跟蹤.格式如下:
[qualifier=][!]value1[,value2]...
qualifier只能是 trace,abbrev,verbose,raw,signal,read,write其中之一.value是用來限定的符號或數字.默認的 qualifier是 trace.感嘆號是否定符號.例如:
-eopen等價于 -e trace=open,表示只跟蹤open調用.而-etrace!=open表示跟蹤除了open以外的其他調用.有兩個特殊的符號 all 和 none.
注意有些shell使用!來執行歷史記錄里的命令,所以要使用\\.
-e trace=set
只跟蹤指定的系統 調用.例如:-e trace=open,close,rean,write表示只跟蹤這四個系統調用.默認的為set=all.
-e trace=file
只跟蹤有關文件操作的系統調用.
-e trace=process
只跟蹤有關進程控制的系統調用.
-e trace=network
跟蹤與網絡有關的所有系統調用.
-e strace=signal
跟蹤所有與系統信號有關的 系統調用
-e trace=ipc
跟蹤所有與進程通訊有關的系統調用
-e abbrev=set
設定 strace輸出的系統調用的結果集.-v 等與 abbrev=none.默認為abbrev=all.
-e raw=set
將指 定的系統調用的參數以十六進制顯示.
-e signal=set
指定跟蹤的系統信號.默認為all.如 signal=!SIGIO(或者signal=!io),表示不跟蹤SIGIO信號.
-e read=set
輸出從指定文件中讀出 的數據.例如:
-e read=3,5
-e write=set
輸出寫入到指定文件中的數據.
-o filename
將strace的輸出寫入文件filename
-p pid
跟蹤指定的進程pid.
-s strsize
指定輸出的字符串的最大長度.默認為32.文件名一直全部輸出.
-u username
以username 的UID和GID執行被跟蹤的命令
用strace查看malloc內存分配
我在博客 c語言內存無法釋放 中曾經提到過 :malloc采用了兩中不同的方式來處理內存申請。
1. 若分配內存小于 128k ,調用 sbrk() ,將堆頂指針向高地址移動,獲得新的虛存空間。
2. 若分配內存大于 128k ,調用 mmap() ,在文件映射區域中分配匿名虛存空間。
現在我們就strace 跟蹤在那篇博客中的 Case #3, 在這之前我先修改 Case #3的代碼,添加代碼(完整的代碼在博客尾部):
int *list;
list = malloc(1024*1024);
free(list);
這段代碼用于查看當申請的內存大于128k時, malloc的處理方法。
strace 跟蹤結果如下:
ubuntu64:~$ strace ./test_mem
execve("./test_mem", ["./test_mem"], [/* 32 vars */]) = 0
. . .
brk(0xd0e000) = 0xd0e000 //通過將堆頂向高地址移動到0xd0e000為進程分配內存
write(1, "before malloc, the top of heap i"..., 43before malloc, the top of heap is 0xced000) = 43
write(1, "address of a is 0xced420 top of "..., 62address of a is 0xced420 top of heap after malloc is 0xd0e000) = 62
brk(0xd40000) = 0xd40000 // 同樣通過移動堆頂分配內存
write(1, "address of a is 0xd06430 top of "..., 62address of a is 0xd06430 top of heap after malloc is 0xd40000) = 62
write(1, "address of a is 0xd1f440 top of "..., 62address of a is 0xd1f440 top of heap after malloc is 0xd40000) = 62
brk(0xd72000) = 0xd72000 // 同樣通過移動堆頂分配內存
write(1, "address of a is 0xd38450 top of "..., 62address of a is 0xd38450 top of heap after malloc is 0xd72000) = 62
write(1, "address of a is 0xd51460 top of "..., 62address of a is 0xd51460 top of heap after malloc is 0xd72000) = 62
brk(0xda4000) = 0xda4000 // 同樣通過移動堆頂分配內存
write(1, "address of a is 0xd6a470 top of "..., 62address of a is 0xd6a470 top of heap after malloc is 0xda4000) = 62
write(1, "address of a is 0xd83480 top of "..., 62address of a is 0xd83480 top of heap after malloc is 0xda4000) = 62
brk(0xdd6000) = 0xdd6000 // 同樣通過移動堆頂分配內存
write(1, "address of a is 0xd9c490 top of "..., 62address of a is 0xd9c490 top of heap after malloc is 0xdd6000) = 62
write(1, "address of a is 0xdb54a0 top of "..., 62address of a is 0xdb54a0 top of heap after malloc is 0xdd6000) = 62
brk(0xe08000) = 0xe08000 // 同樣通過移動堆頂分配內存
write(1, "address of a is 0xdce4b0 top of "..., 62address of a is 0xdce4b0 top of heap after malloc is 0xe08000) = 62
//用mmap在文件映射區為進程分配內存
mmap(NULL, 1052672, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f0cd5140000
write(1, "malloc end\n", 11malloc end) = 11
write(1, "before free, the top of heap is "..., 41before free, the top of heap is 0xe08000) = 41
brk(0xd0e000) = 0xd0e000 //釋放通過brk移動堆頂分配的內存
write(1, "after free, the top of heap is "..., 41after free, the top of heap is 0xd0e000) = 41
munmap(0x7f0cd5140000, 1052672) = 0 //釋放mmap分配的內存
exit_group(0) = ?
+++ exited with 0 +++
結果中省略了程序加載部分內容,從輸出結果可以看出:
1. 在為鏈表申請節點時, 因為每個節點size小于128k(128k是可以調整的),?malloc直接通過brk()函數在堆上分配內存。
2. 為list分配內存時,因為它需要1M內存, 所以malloc通過mmap()函數在在文件映射區域分配內存。
附錄
1. 32位系統中進程虛擬空間布局
2. Case #3代碼
#include
#include
#include
#include
typedef struct node
{
char a[1024*100];
struct node *next;
}node;
int main()
{
node *node_first = NULL, *node_now;
node *a;
int i;
char s_cmd[100];
sprintf(s_cmd, "pmap -d %lu | grep mapped", getpid());
printf("before malloc, the top of heap is 0x%lx\n", sbrk(0));
for(i=0;i<10;i++){
a=(node *)malloc(sizeof(node));
a->next=NULL;
if(node_first==NULL) node_first=a;
else node_now->next=a;
node_now=a;
printf("address of a is 0x%lx ", a);
printf("top of heap after malloc is 0x%lx\n", sbrk(0));
}
int *list;
list = malloc(1024*1024);
printf("malloc end\n");
printf("before free, the top of heap is 0x%lx\n", sbrk(0));
while(node_first!=NULL)
{
node_now=node_first->next;
free(node_first);
node_first=node_now;
}
printf("after free, the top of heap is 0x%lx\n", sbrk(0));
free(list);
return 0;
}
參考
總結
以上是生活随笔為你收集整理的linux 跟踪内存,用strace跟踪malloc内存分配的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 新股开盘多久会涨停板?
- 下一篇: linux用if语句编程序,Shell