內(nèi)存泄漏:
分配的內(nèi)存不足以放下數(shù)據(jù)項序列,稱為內(nèi)存溢出。一個盤子 用盡各種方法只能裝4 個果子,你裝了5個偶摔,結(jié)果掉倒地上不能吃了。這就是溢出促脉!比方說棧辰斋,棧滿時再做進(jìn)棧必定產(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)這樣的代碼一旦運行,錯誤就在所難免愿卸,會帶來的后果也是不確定的灵临,通常可能會造成如下后果:
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)境一致甸昏。