C語言內存泄漏之free、valgrind、examine


先來介紹valgrind和examine這兩個工具的使用。

使用examine命令(簡寫是x)來查看內存地址中的值。x命令的語法如下所示:
x/<n/f/u> <addr>
n、f、u是可選的參數。
n 是一個正整數,表示顯示內存的長度。

f 表示顯示的格式,其取值如下:

x 按十六進制格式顯示變量
d 十進制
u 十六進制無符號整型
o 八進制
t 二進制
c 字符
s 字符串
f 浮點數
i 指令

u 表示從當前地址往后請求的字節數,其取值如下:

b表示單字節
h表示雙字節
w表示四字 節(默認)
g表示八字節

Valgrind 可以對編譯后的二進制程序進行內存使用監測(C語言中的malloc和free,以及C++中的new和delete),找出內存泄漏問題。
Valgrind 中包含的 Memcheck 工具可以檢查以下的程序錯誤:

使用未初始化的內存 (Use of uninitialised memory)
使用已經釋放了的內存 (Reading/writing memory after it has been free’d)
使用超過malloc分配的內存空間(Reading/writing off the end of malloc’d blocks)
對堆棧的非法訪問 (Reading/writing inappropriate areas on the stack)
申請的空間是否有釋放 (Memory leakswhere pointers to malloc’d blocks are lost forever)
malloc/free/new/delete申請和釋放內存的匹配(Mismatched use of malloc/new/new [] vs free/delete/delete [])
src和dst的重疊(Overlapping src and dst pointers in memcpy() and related functions)
重復free

一般這樣使用就可以了:valgrind   --tool=memcheck   --leak-check=full   ./test

常見錯誤解釋:

Invalid write of size 4

這可能是數組越界了

40 bytes in 1 blocks are definitely lost in loss record 1 of 1

內存沒有釋放

下面講一下malloc()和free()到底干了些什么事

malloc()之后這片內存就是你的了,你就擁有使用權了。

free()只是將你以前申請的內存塊插入到 heap 中,並檢測是否與 heap 中已有的內存塊相鄰,如相鄰,則合並這兩塊,至於你自己定義的指針,仍保持原值,但已沒有空間,需要你自己手動將其 指向 NULL。

free並沒有把內存里的值清0,內存里的值仍保持原樣。free之后仍然可以通過你的指針去訪問內存,如果這片內存沒有並操作系統挪作他用,那你訪問到的還是原來的值。當然你這樣做是很危險的,尤其在多線程環境下,你根本不知道這片內存是否並操作系統挪作他用了。

解決一下下面的問題。

 1 #include<stdio.h>
2 #include<string.h>
3 #include<stdlib.h>
4
5 struct url{
6 char *domain;
7 char *path;
8 int depth;
9 };
10
11 void getUrl(struct url* rect){
12 char *line;
13 line=calloc(128,sizeof(char));
14 strcpy(line,"http://www.baidu.com /gaoji/preferences.html 2");
15 char *delim=" ";
16 rect->domain=strtok(line,delim);
17 rect->path=strtok(NULL,delim);
18 rect->depth=atoi(strtok(NULL,delim));
19 free(line);
20 }
21
22 main(){
23 struct url* rect;
24 rect=calloc(1,sizeof(struct url));
25 getUrl(rect);
26 printf("|%s|%s|%d|\n",rect->domain,rect->path,rect->depth);
27 free(rect);
28 printf("%s\n",rect->path);
29 printf("%d\n",sizeof(struct url));
30 }

結果輸出sizeof(struct url)為12。想一想為什么?兩個指針加一個int當然是12字節了。

在19行free掉line之后,按照常理,rect->domain,rect->path,rect->depth就已經不能再使用了,因為它們指向的都是line里面的內容。但是我們卻用rect->domain,rect->path,rect->depth訪問到了內存中相應的值。這就解釋了free到底做了什么。

使用valgrind檢測內存使用是否有問題:$ valgrind --tool=memcheck --leak-check=full ./mem

下面是截取的一些命令輸出片段:

==9763== Invalid read of size 1
==9763== at 0x407FD6E: vfprintf (vfprintf.c:1620)
==9763== by 0x408789F: printf (printf.c:35)
==9763== by 0x80485DC: main (mem.c:26)
==9763== Address 0x41a3068 is 0 bytes inside a block of size 128 free'd
==9763== at 0x4025BF0: free (vg_replace_malloc.c:366)
==9763== by 0x804857F: getUrl (mem.c:19)
==9763== by 0x80485AF: main (mem.c:25)


==9763== Invalid read of size 4
==9763== at 0x80485ED: main (mem.c:28)
==9763== Address 0x41a302c is 4 bytes inside a block of size 12 free
'd
==9763== at 0x4025BF0: free (vg_replace_malloc.c:366)
==9763== by 0x80485E8: main (mem.c:27)


==9763== HEAP SUMMARY:
==9763== in use at exit: 0 bytes in 0 blocks
==9763== total heap usage: 2 allocs, 2 frees, 140 bytes allocated
==9763==
==9763== All heap blocks were freed -- no leaks are possible
”Address 0x41a302c is 4 bytes inside a block of size 12 free'd“這句話翻譯過來大概就是說要訪問的地址0x41a302c已經在被free掉的內存塊中了。
”total heap usage: 2 allocs, 2 frees, 140bytes allocated“--line是128字節,sizeof(structurl)=12,所以一共是140字節,alloc了2次,free了2次,所以no leaks are possible。
我們把斷點設在16、20、28行,來看一下free之后,指針存儲的地址變了沒,通過該指針還能否訪問內存。

為了使26行”合法“運行,我們把19行注釋掉。這時用valgrind工具又會檢查出”可能“有內存泄漏--事實上也確實是有內存泄漏。

報告說alloc了2次,free了1次,可能在一個塊里面有128 bytes的內存泄漏。
這line變量free也不是,不free也不是,腫么辦?
解決辦法:
 1 #include<stdio.h>
2 #include<string.h>
3 #include<stdlib.h>
4
5 struct url{
6 char *domain;
7 char *path;
8 int depth;
9 };
10
11 void freeUrl(struct url* rect){
12 free(rect->domain);
13 free(rect->path);
14 free(rect);
15 }
16
17 void getUrl(struct url* rect){
18 char *line;
19 line=calloc(128,sizeof(char));
20 strcpy(line,"http://www.baidu.com /gaoji/preferences.html 2");
21 char *delim=" ";
22 char *d=calloc(40,sizeof(char));
23 char *p=calloc(80,sizeof(char));
24 strcpy(d,strtok(line,delim));
25 strcpy(p,strtok(NULL,delim));
26 rect->domain=d;
27 rect->path=p;
28 rect->depth=atoi(strtok(NULL,delim));
29 free(line);
30 }
31
32 main(){
33 struct url* rect;
34 rect=calloc(1,sizeof(struct url));
35 printf("%d\n",sizeof(struct url));
36 getUrl(rect);
37 printf("|%s|%s|%d|\n",rect->domain,rect->path,rect->depth);
38 freeUrl(rect);
39 }

valgrind沒有檢查出任何問題:




免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM