這篇文章主要是針對c++程式中可能出現的記憶體錯誤做一些間單的歸納。是看了Rational Purify的使用和分析之後做的提煉。相信很多初級的c++程式員也像我一樣曾被這些問題困惑,希望對各位看官有所協助。
一、記憶體錯誤的分類
a.記憶體訪問錯誤
對記憶體進行讀或寫時發生的錯誤,可能是讀未被初始化的記憶體單元,也可能是讀寫錯誤的記憶體單元。
b.記憶體使用量錯誤
主要是在動態請求記憶體之後沒有正確釋放產生的錯誤。
二、記憶體剖析(典型的c++記憶體模型)
BSS段:BSS段(bss segment)通常是指用來存放程式中未初始化的全域變數的一塊記憶體地區。BSS是英文Block Started by Symbol的簡稱。BSS段屬於靜態記憶體配置。
資料區段:資料區段(data segment)通常是指用來存放程式中已初始化的全域變數的一塊記憶體地區。資料區段屬於靜態記憶體配置。(其實我不太明白既然都是存全域變數的,那為什麼要把已初始化的和未初始化的分開在兩個段中進行管理)
程式碼片段:程式碼片段(code segment/text segment)通常是指用來存放程式執行代碼的一塊記憶體地區。這部分地區的大小在程式運行前就已經確定,並且記憶體地區通常屬於唯讀, 某些架構也允許程式碼片段為可寫,即允許修改程式。在程式碼片段中,也有可能包含一些唯讀常數變數,例如字串常量等。
堆(heap):堆是用於存放進程運行中被動態分配的記憶體段,它的大小並不固定,可動態擴張或縮減。當進程調用malloc等函數分配記憶體時,新分配的記憶體就被動態添加到堆上(堆被擴張);當利用free等函數釋放記憶體時,被釋放的記憶體從堆中被剔除(堆被縮減)
棧(stack):棧又稱堆棧, 是使用者存放程式臨時建立的局部變數,也就是說我們函數括弧“{}”中定義的變數(但不包括static聲明的變數,static意味著在資料區段中存放變數)。除此以外,在函數被調用時,其參數也會被壓入發起調用的進程棧中,並且待到調用結束後,函數的傳回值也會被存放回棧中。由於棧的先進先出特點,所以棧特別方便用來儲存/恢複調用現場。從這個意義上講,我們可以把堆棧看成一個寄存、交換臨時資料的記憶體區。
c++不同於C#、Java的一個地方是它可以動態管理記憶體,但魚與熊掌兩者不可兼得,靈活性的代價是程式員需要花費更多的精力保證代碼不發生記憶體錯誤。
三、常見的記憶體訪問錯誤和記憶體使用量錯誤
具體來說,記憶體訪問錯誤有下面這幾種:訪問未被初始化的記憶體單元、數組訪問錯誤、訪問無效的記憶體單元(0x000000,0x000005等)、寫無效記憶體。
而記憶體使用量錯誤有:1、請求記憶體之後沒有將它釋放,使new和delete成對出現可以避免這樣的問題。2、釋放一塊記憶體後又再釋放一次。
四、例子
1 #include <iostream>2 using namespace std;3 int main(){4 char* str1="four";5 char* str2=new char[4]; //not enough space6 char* str3=str2;7 cout<<str2<<endl; //UMR8 strcpy(str2,str1); //ABW9 cout<<str2<<endl; //ABR10 delete str2;11 str2[0]+=2; //FMR and FMW12 delete str3; //FFM13 } UMR:Uninitialized Memery Read.讀未初始化記憶體 ABW:Array Bound Write.數組越界寫 FMR/W:Freed Memery Read/Write.讀/寫已被釋放的記憶體 FFM:Free Freed Memery.釋放已被釋放的記憶體 由以上的程式,我們可以看到:在第5行分配記憶體時,忽略了字串終止符"/0"所佔空間導致了第8行的數組越界寫(Array Bounds Write)和第9行的數組越界讀(Array Bounds Read); 在第7行,列印尚未賦值的str2將產生訪問未初始化記憶體錯誤(Uninitialized Memory Read);在第11行使用已經釋放的變數將導致釋放記憶體讀和寫錯誤(Freed Memory Read and Freed Memory Write);最後由於str3和str2所指的是同一片記憶體,第12行又一次釋放了已經被釋放的空間 (Free Freed Memory)。
這個包含許多錯誤的程式可以編譯串連,而且可以在很多平台上運行。但是這些錯誤就像定時炸彈,會在特殊配置下觸發,造成不可預見的錯誤。這就是記憶體錯誤難以發現的一個主要原因。
本文來自CSDN部落格,轉載請標明出處:http://blog.csdn.net/FuXiaoZhuan/archive/2008/10/18/3096839.aspx