全國(guó)咨詢(xún)/投訴熱線:400-618-4000

首頁(yè)技術(shù)文章正文

Linux下C和C++程序中內(nèi)存泄露檢測(cè)

更新時(shí)間:2020-01-16 來(lái)源:黑馬程序員 瀏覽量:

01. 前言

C/C++運(yùn)行高效,不管是操作系統(tǒng)內(nèi)核還是對(duì)性有要求的程序(比如游戲引擎)都要求使用C/C++來(lái)編寫(xiě),其實(shí)C/C++強(qiáng)大的一點(diǎn)在于能夠使用指針自由地控制內(nèi)存的使用,適時(shí)的申請(qǐng)內(nèi)存和釋放內(nèi)存,從而做到其他編程語(yǔ)言做不到的高效地運(yùn)行。但是內(nèi)存管理是一把雙刃劍,用好了削鐵如泥,用不好自斷一臂。在申請(qǐng)堆上內(nèi)存使用完之后中如果做不到適時(shí)有效的釋放,那么就會(huì)造成內(nèi)存泄露,久而久之程序就會(huì)將系統(tǒng)內(nèi)存耗盡,導(dǎo)致系統(tǒng)運(yùn)行出問(wèn)題。就如同你每天跑去圖書(shū)館借一打書(shū)籍而不還,直到圖書(shū)館倒閉為止。

C語(yǔ)言中申請(qǐng)內(nèi)存和釋放內(nèi)存的方法是使用 malloc和free。

C++中能兼容C,所以也能使用malloc和free,面向?qū)ο蟮那闆r下使用的則是new和delete,能夠自動(dòng)執(zhí)行構(gòu)造函數(shù)和析構(gòu)函數(shù)。

在Linux平臺(tái),我們可以使用valgrind命令檢測(cè)C/C++程序是否內(nèi)存泄露。

 

02. valgrind安裝

debian/ubuntu下安裝方法:

 deng@itcast:~$ sudo apt install valgrind
 deng@itcast:~$ sudo yum install valgrind


安裝好valgrind工具之后,下面來(lái)看看valgrind的幾個(gè)應(yīng)用場(chǎng)景。

redhat/centos下安裝方法:


03. 使用未初始化的內(nèi)存

程序中我們定義了一個(gè)指針p,但并未給他分配空間,但我們卻使用它了。

程序示例:

 #include <stdio.h>
 #include <string.h>
 #include <stdlib.h>
 
 int main(void)
 {
     char ch;
     char *p;
 
     ch = *p;
 
     printf("ch = %c\n", ch);
 
     return 0;
 }

valgrind檢測(cè)出到我們的程序使用了未初始化的變量。

1579143350462_C++內(nèi)存泄露01.jpg


04. 使用野指針

p所指向的內(nèi)存被釋放了,p變成了野指針,但是我們卻繼續(xù)使用這片內(nèi)存。

程序示例:

 #include <stdio.h>
 #include <string.h>
 #include <stdlib.h>
 
 int main(void)
 {
     int *p = NULL;
 
     p = malloc(sizeof(int));
     if (NULL == p)
    {  
         printf("malloc failed...\n");
         return 1;
    }  
     memset(p, 0, sizeof(int));
 
     *p = 88;
 
     printf("*p = %d\n", *p);
 
     //釋放內(nèi)存
     free(p);
 
     printf("*p = %d\n", *p);
 
     return 0;
 }

valgrind檢測(cè)到我們使用了已經(jīng)free的內(nèi)存,并給出這片內(nèi)存是哪里分配和哪里釋放的。

1579143360325_C++內(nèi)存泄露02.jpg


05. 動(dòng)態(tài)內(nèi)存越界訪問(wèn)

我們動(dòng)態(tài)地分配了一片連續(xù)的存儲(chǔ)空間,但我們?cè)谠L問(wèn)個(gè)數(shù)組時(shí)發(fā)生了越界訪問(wèn)。

程序示例:

 #include <stdio.h>
 #include <string.h>
 #include <stdlib.h>
 
 int main(void)
 {
     int i = 0;
     int *p = NULL;
 
     p = malloc(5 * sizeof(int));
     if (NULL == p)
    {  
         printf("malloc failed...\n");
         return 1;
    }  
     memset(p, 0, 10 * sizeof(int));
 
     for (int i = 0; i <= 5; i++)
    {  
         p[i] = i + 1;  
    }  
 
     for (int i = 0; i <= 5; i++)
    {  
         printf("p[%d]: %d\n", i, p[i]);
    }  
 
     return 0;
 }

valgrind檢測(cè)出越界信息如下。

1579143369216_C++內(nèi)存泄露03.jpg



注意:

valgrind不檢查非動(dòng)態(tài)分配數(shù)組的使用情況。


06. 分配空間后沒(méi)有釋放

內(nèi)存泄漏的原因在于我們使用free或者new分配空間之后,沒(méi)有使用free或者delete釋放內(nèi)存。

程序示例:

 #include <stdio.h>
 #include <string.h>
 #include <stdlib.h>
 
 int main(void)
 {
     int *p = NULL;
 
     p = malloc(sizeof(int));
         
     *p = 88;
 
     printf("*p = %d\n", *p);
 
     return 0;
 }

valgrind的記錄顯示上面的程序用了1次malloc,卻調(diào)用了0次free。


1579143379144_C++內(nèi)存泄露04.jpg

可以使用--leak-check=full進(jìn)一步獲取內(nèi)存泄漏的信息,比如malloc具體行號(hào)。

 

1579143388901_C++內(nèi)存泄露05.jpg


07. 不匹配使用delete或者free

一般我們使用malloc分配的空間,必須使用free釋放內(nèi)存。使用new分配的空間,使用delete釋放內(nèi)存。

程序示例:

 #include <stdio.h>
 #include <string.h>
 #include <stdlib.h>
 
 int main(void)
 {
     int *p = NULL;
 
     p = (int *)malloc(sizeof(int));
     
     *p = 88;
 
     printf("*p = %d\n", *p);
 
     delete p;
 
     return 0;
 }

不匹配地使用malloc/new/new[] 和 free/delete/delete[]則會(huì)被提示mismacth

 

1579143403216_C++內(nèi)存泄露06.jpg


08. 兩次釋放同一塊內(nèi)存

一般情況下,內(nèi)存分配一次,只釋放一次。如果多次釋放,可能會(huì)出現(xiàn)double free。

程序示例:

 #include <stdio.h>
 #include <string.h>
 #include <stdlib.h>
 
 int main(void)
 {
     int *p = NULL;
 
     p = (int *)malloc(sizeof(int));
     
     *p = 88;
 
     printf("*p = %d\n", *p);
 
     free p;
  free p;
     
     return 0;
 }

多次釋放同一內(nèi)存,出現(xiàn)非法釋放內(nèi)存。

1579143411187_C++內(nèi)存泄露07.jpg


09. 總結(jié)

內(nèi)存泄露問(wèn)題非常難定位,對(duì)于小工程項(xiàng)目來(lái)說(shuō),簡(jiǎn)單去檢查代碼中new和delete的匹配對(duì)數(shù)就基本能定位到問(wèn)題,但是一旦代碼量上升到以萬(wàn)單位時(shí),僅靠肉眼檢查來(lái)定位問(wèn)題那就非常困難了,所以我們需要利用工具幫助我們找出問(wèn)題所在。在Linux系統(tǒng)下內(nèi)存檢測(cè)工具首推Valgrind,一款非常好用的開(kāi)源內(nèi)存管理工具。Valgrind其實(shí)是一個(gè)工具集,內(nèi)存錯(cuò)誤檢測(cè)只是它眾多功能的一個(gè),但我們用得最多的功能正是它——memcheck。推薦了解黑馬程序員C++培訓(xùn)課程。

總之,valgrind工具可以檢測(cè)下列與內(nèi)存相關(guān)的問(wèn)題 :

· 未釋放內(nèi)存的使用

· 對(duì)釋放后內(nèi)存的讀/寫(xiě)

· 對(duì)已分配內(nèi)存塊尾部的讀/寫(xiě)

· 內(nèi)存泄露

· 不匹配的使用malloc/new/new[] 和 free/delete/delete[]

· 重復(fù)釋放內(nèi)存

猜你喜歡:
c語(yǔ)言入門(mén)教程下載


分享到:
在線咨詢(xún) 我要報(bào)名
和我們?cè)诰€交談!