內(nèi)存泄漏:
分配的內(nèi)存不足以放下數(shù)據(jù)項序列,稱為內(nèi)存溢出。一個盤子 用盡各種方法只能裝4 個果子,你裝了5個,結(jié)果掉倒地上不能吃了。這就是溢出!比方說棧,棧滿時再做進棧必定產(chǎn)生空間溢出,叫上溢,棧空時再做退棧也產(chǎn)生空間溢出,稱為下溢。
以發(fā)生的方式來分類,內(nèi)存泄漏可以分為4 類:
常發(fā)性內(nèi)存泄漏。發(fā)生內(nèi)存泄漏的代碼會被多次執(zhí)行到,每次被
執(zhí)行的時候都會導(dǎo)致一塊內(nèi)存泄漏。偶發(fā)性內(nèi)存泄漏。發(fā)生內(nèi)存泄漏的代碼只有在某些特定環(huán)境或操
作過程下才會發(fā)生。常發(fā)性和偶發(fā)性是相對的。對于特定的環(huán)境,偶
發(fā)性的也許就變成了常發(fā)性的。所以測試環(huán)境和測試方法對檢測內(nèi)存
泄漏至關(guān)重要。一次性內(nèi)存泄漏。發(fā)生內(nèi)存泄漏的代碼只會被執(zhí)行一次,或者由
于算法上的缺陷,導(dǎo)致總會有一塊僅且一塊內(nèi)存發(fā)生泄漏。比如,在
類的構(gòu)造函數(shù)中分配內(nèi)存,在析構(gòu)函數(shù)中卻沒有釋放該內(nèi)存,所以內(nèi)
存泄漏只會發(fā)生一次。隱式內(nèi)存泄漏。程序在運行過程中不停的分配內(nèi)存,但是直到結(jié)
束的時候才釋放內(nèi)存。嚴(yán)格的說這里并沒有發(fā)生內(nèi)存泄漏,因為最終
程序釋放了所有申請的內(nèi)存。但是對于一個服務(wù)器程序,需要運行幾
天,幾周甚至幾個月,不及時釋放內(nèi)存也可能導(dǎo)致最終耗盡系統(tǒng)的所
有內(nèi)存。所以,我們稱這類內(nèi)存泄漏為隱式內(nèi)存泄漏。
從用戶使用程序的角度來看,內(nèi)存泄漏本身不會產(chǎn)生什么危害,作為
一般的用戶,根本感覺不到內(nèi)存泄漏的存在。真正有危害的是內(nèi)存泄
漏的堆積,這會最終消耗盡系統(tǒng)所有的內(nèi)存。從這個角度來說,一次
性內(nèi)存泄漏并沒有什么危害,因為它不會堆積,而隱式內(nèi)存泄漏危害
性則非常大,因為較之于常發(fā)性和偶發(fā)性內(nèi)存,泄漏它更難被檢測到
====================================================
內(nèi)存越界:
何謂內(nèi)存訪問越界,簡單的說,你向系統(tǒng)申請了一塊內(nèi)存,在使用這塊內(nèi)存的時候,超出了你申請的范圍。
內(nèi)存越界使用,這樣的錯誤引起的問題存在極大的不確定性,有時大,有時小,有時可能不會對程序的運行產(chǎn)生影響,正是這種不易重現(xiàn)的錯誤,才是最致命的,一旦出錯破壞性極大。
什么原因會造成內(nèi)存越界使用呢?有以下幾種情況,可供參考:
例1:
char buf[32] = {0};
for(int i=0; i<n; i++)// n < 32 or n > 32
{
buf[i] = 'x';
}
....
例2:
char buf[32] = {0};
string str = "this is a test sting !!!!";
sprintf(buf, "this is a test buf!string:%s", str.c_str()); //out of buffer space
....
例3:
string str = "this is a test string!!!!";
char buf[16] = {0};
strcpy(buf, str.c_str()); //out of buffer space
類似的還存在隱患的函數(shù)還有:strcat,vsprintf等
同樣,memcpy, memset, memmove等一些內(nèi)存操作函數(shù)在使用時也一定要注意。
當(dāng)這樣的代碼一旦運行,錯誤就在所難免,會帶來的后果也是不確定的,通??赡軙斐扇缦潞蠊?/p>
1.破壞了堆中的內(nèi)存分配信息數(shù)據(jù),特別是動態(tài)分配的內(nèi)存塊的內(nèi)存信息數(shù)據(jù),因為操作系統(tǒng)在分配和釋放內(nèi)存塊時需要訪問該數(shù)據(jù),一旦該數(shù)據(jù)被破壞,以下的幾種情況都可能會出現(xiàn)。
*** glibc detected *** free(): invalid pointer:
*** glibc detected *** malloc(): memory corruption:
*** glibc detected *** double free or corruption (out): 0x00000000005c18a0 ***
*** glibc detected *** corrupted double-linked list: 0x00000000005ab150 ***
2.破壞了程序自己的其他對象的內(nèi)存空間,這種破壞會影響程序執(zhí)行的不正確性,當(dāng)然也會誘發(fā)coredump,如破壞了指針數(shù)據(jù)。
3.破壞了空閑內(nèi)存塊,很幸運,這樣不會產(chǎn)生什么問題,但誰知道什么時候不幸會降臨呢?
通常,代碼錯誤被激發(fā)也是偶然的,也就是說之前你的程序一直正常,可能由于你為類增加了兩個成員變量,或者改變了某一部分代碼,coredump就頻繁發(fā)生,而你增加的代碼絕不會有任何問題,這時你就應(yīng)該考慮是否是某些內(nèi)存被破壞了。
排查的原則,首先是保證能重現(xiàn)錯誤,根據(jù)錯誤估計可能的環(huán)節(jié),逐步裁減代碼,縮小排查空間。
檢查所有的內(nèi)存操作函數(shù),檢查內(nèi)存越界的可能。常用的內(nèi)存操作函數(shù):
sprintf snprintf
vsprintf vsnprintf
strcpy strncpy strcat
memcpy memmove memset bcopy
如果有用到自己編寫的動態(tài)庫的情況,要確保動態(tài)庫的編譯與程序編譯的環(huán)境一致。