內(nèi)存泄露的原因
內(nèi)存泄漏是怎么回事?為什么會(huì)內(nèi)存泄漏?內(nèi)存泄露的原因是什么?下面就由學(xué)習(xí)啦小編告訴大家內(nèi)存泄露的原因吧!
內(nèi)存泄漏是什么
簡(jiǎn)單的說就是申請(qǐng)了一塊內(nèi)存空間,使用完畢后沒有釋放掉。它的一般表現(xiàn)方式是程序運(yùn)行時(shí)間越長(zhǎng),占用內(nèi)存越多,最終用盡全部?jī)?nèi)存,整個(gè)系統(tǒng)崩潰。由程序申請(qǐng)的一塊內(nèi)存,且沒有任何一個(gè)指針指向它,那么這塊內(nèi)存就泄露了。
內(nèi)存泄露的原因
1.new,malloc后沒有delete,free
2.創(chuàng)建內(nèi)核對(duì)象(比如CreateFile,CreateMutex,CreateThread),后沒有釋放內(nèi)核對(duì)象句柄.
3.創(chuàng)建內(nèi)存映射文件,CreateFileMapping,MapViewOfFile后沒有CloseHandle(),UnMapviewofFile
4.創(chuàng)建GDI對(duì)象后,比如LoadIcon,LoadImage,CreateImageList等等,沒有Destroy掉
5.創(chuàng)建DC后,比如GetDC(), 沒有釋放DC句柄
6.保留虛擬地址空間 VirtualAlloc(),然后提交物理存儲(chǔ)器后,沒有釋放掉。
內(nèi)存泄漏的分類
以發(fā)生的方式來分類,內(nèi)存泄漏可以分為4類:
(1). 常發(fā)性內(nèi)存泄漏。
發(fā)生內(nèi)存泄漏的代碼會(huì)被多次執(zhí)行到,每次被執(zhí)行的時(shí)候都會(huì)導(dǎo)致一塊內(nèi)存泄漏。
(2). 偶發(fā)性內(nèi)存泄漏。
發(fā)生內(nèi)存泄漏的代碼只有在某些特定環(huán)境或操作過程下才會(huì)發(fā)生。常發(fā)性和偶發(fā)性是相對(duì)的。對(duì)于特定的環(huán)境,偶發(fā)性的也許就變成了常發(fā)性的。所以測(cè)試環(huán)境和測(cè)試方法對(duì)檢測(cè)內(nèi)存泄漏至關(guān)重要。
(3). 一次性內(nèi)存泄漏。
發(fā)生內(nèi)存泄漏的代碼只會(huì)被執(zhí)行一次,或者由于算法上的缺陷,導(dǎo)致總會(huì)有一塊僅且一塊內(nèi)存發(fā)生泄漏。比如,在類的構(gòu)造函數(shù)中分配內(nèi)存,在析構(gòu)函數(shù)中卻沒有釋放該內(nèi)存,所以內(nèi)存泄漏只會(huì)發(fā)生一次。
(4). 隱式內(nèi)存泄漏。
程序在運(yùn)行過程中不停的分配內(nèi)存,但是直到結(jié)束的時(shí)候才釋放內(nèi)存。嚴(yán)格的說這里并沒有發(fā)生內(nèi)存泄漏,因?yàn)樽罱K程序釋放了所有申請(qǐng)的內(nèi)存。但是對(duì)于一個(gè)服務(wù)器程序,需要運(yùn)行幾天,幾周甚至幾個(gè)月,不及時(shí)釋放內(nèi)存也可能導(dǎo)致最終耗盡系統(tǒng)的所有內(nèi)存。所以,我們稱這類內(nèi)存泄漏為隱式內(nèi)存泄漏。
內(nèi)存泄漏的危害
從用戶使用程序的角度來看,內(nèi)存泄漏本身不會(huì)產(chǎn)生什么危害,作為一般的用戶,根本感覺不到內(nèi)存泄漏的存在。真正有危害的是內(nèi)存泄漏的堆積,這會(huì)最終消耗盡系統(tǒng)所有的內(nèi)存。從這個(gè)角度來說,一次性內(nèi)存泄漏并沒有什么危害,因?yàn)樗粫?huì)堆積,而隱式內(nèi)存泄漏危害性則非常大,因?yàn)檩^之于常發(fā)性和偶發(fā)性內(nèi)存泄漏它更難被檢測(cè)到。
內(nèi)存泄漏的表現(xiàn)
內(nèi)存泄漏或者是說,資源耗盡后,系統(tǒng)會(huì)表現(xiàn)出什么現(xiàn)象哪?
cpu資源耗盡:估計(jì)是機(jī)器沒有反應(yīng)了,鍵盤,鼠標(biāo),以及網(wǎng)絡(luò)等等。這個(gè)在windows上經(jīng)??匆?,特別是中了毒。
進(jìn)程id耗盡:沒法創(chuàng)建新的進(jìn)程了,串口或者telnet都沒法創(chuàng)建了。
硬盤耗盡: 機(jī)器要死了,交換內(nèi)存沒法用,日志也沒法用了,死是很正常的。
內(nèi)存泄漏或者內(nèi)存耗盡:新的連接無(wú)法創(chuàng)建,free的內(nèi)存比較少。發(fā)生內(nèi)存泄漏的程序很多,但是要想產(chǎn)生一定的后果,就需要這個(gè)進(jìn)程是無(wú)限循環(huán)的,是個(gè)服務(wù)進(jìn)程。當(dāng)然,內(nèi)核也是無(wú)限循環(huán)的,所以,如果內(nèi)核發(fā)生了內(nèi)存泄漏,情況就更加不妙。內(nèi)存泄漏是一種很難定位和跟蹤的錯(cuò)誤,目前還沒看到有什么好用的工具(當(dāng)然,用戶空間有一些工具,有靜態(tài)分析的,也會(huì)動(dòng)態(tài)分析的,但是找內(nèi)核的內(nèi)存泄漏,沒有好的開源工具)
內(nèi)存泄漏和對(duì)象的引用計(jì)數(shù)有很大的關(guān)系,再加上c/c++都沒有自動(dòng)的垃圾回收機(jī)制,如果沒有手動(dòng)釋放內(nèi)存,問題就會(huì)出現(xiàn)。如果要避免這個(gè)問題,還是要從代碼上入手,良好的編碼習(xí)慣和規(guī)范,是避免錯(cuò)誤的不二法門。
一般我們常說的內(nèi)存泄漏是指堆內(nèi)存的泄漏。
堆內(nèi)存是指程序從堆中分配的,大小任意的(內(nèi)存塊的大小可以在程序運(yùn)行期決定),使用完后必須顯示釋放的內(nèi)存。
應(yīng)用程序一般使用malloc,realloc,new等函數(shù)從堆中分配到一塊內(nèi)存,使用完后,程序必須負(fù)責(zé)相應(yīng)的調(diào)用free或delete釋放該內(nèi)存塊,否則,這塊內(nèi)存就不能被再次使用,我們就說這塊內(nèi)存泄漏了。