彻底理解内存泄漏,memory leak
作者 | 碼農(nóng)的荒島求生
來源 | 碼農(nóng)的荒島求生
內(nèi)存申請就好比去停車場找停車位,找到停車位后你就可以把車停在這里。
從這個類比看什么是內(nèi)存泄漏呢?內(nèi)存泄漏看上去是停車場的車輛只進不出導致最終找不到停車位,從程序員的角度看就是內(nèi)存只申請取不釋放,如果你去問,可能有不少人認為內(nèi)存泄漏就是這么回事。
然而這其實是不全面的。
申請過多內(nèi)存
首先內(nèi)存只申請不釋放未必就是內(nèi)存泄漏,有可能是你的程序的確需要申請很多內(nèi)存,這是正常的,然而如果是bug導致申請了很多內(nèi)存,這就是內(nèi)存泄漏了,或者也有人將其稱為space leak,意思是申請的內(nèi)存超過了正常所需;不管是有意無意,總之在這種情況下你依然保持對這些內(nèi)存的引用,因此你總可以找到這些內(nèi)存并刪除它們,就看你刪不刪。
有很多情況會導致這一問題,像重復(fù)使用的某個結(jié)構(gòu)體/對象,當再次復(fù)用時沒有清理上一次使用遺留的數(shù)據(jù)、系統(tǒng)中存在cache,但cache的過期策略設(shè)置不得當?shù)鹊取?/p>
內(nèi)存無法刪除
另一類比較有趣的內(nèi)存泄漏是說你申請了一些內(nèi)存,但最終卻沒有什么指向它們:
void memory_leak() {char* mem = (char*)malloc(1024);// just return }在這段代碼中我們申請了1k內(nèi)存,然而當memory_leak函數(shù)返回后你就再也不知道這段內(nèi)存到底在哪里了!
用停車場的示例來說就是有些司機太過土豪,家里的車太多以至于把將車放在停車場這件事忘掉了,導致這些車根本就不會有人再開走,因此白白浪費停車位,并導致可用車位越來越少,而對于編程來說就是粗心大意的程序員申請了一些內(nèi)存后最終“忘掉”了,再也不會有什么東西(變量/指針)指向這些內(nèi)存,因此在這種情況下你沒有辦法再找到這些內(nèi)存并將其刪除。
內(nèi)存碎片
這也算的上是一類特殊的內(nèi)存泄漏,用停車場的例子來說就是兩個停車位中間停靠了一輛小型老年代步車,導致盡管這兩個停車位剩余的空間足夠大但又恰好都沒有辦法再停靠一輛小汽車。
假定我們系統(tǒng)中寶貴的內(nèi)存大小只有8字節(jié),其中有兩個字節(jié)已經(jīng)分配出去了,就像這樣:
現(xiàn)在,系統(tǒng)中空閑的內(nèi)存是6字節(jié),下一次的內(nèi)存申請需要分配5字節(jié),糟糕,我們已經(jīng)沒有辦法再找到連續(xù)的5個字節(jié)大小的內(nèi)存空間了,盡管全部空間的內(nèi)存還有6字節(jié),這就是所謂的內(nèi)存碎片問題。
而對于內(nèi)存分配器來說如果出現(xiàn)這種情況那么將不得不借助操作系統(tǒng)的幫助來擴大堆區(qū),因此看起來我們的程序占據(jù)的內(nèi)存越來越多,盡管實際上程序可能并不需要那么多內(nèi)存,僅僅是因為內(nèi)存碎片的原因?qū)е乱徊糠謨?nèi)存無法被再次被利用起來。
然而對于現(xiàn)代操作系統(tǒng)尤其具備虛擬內(nèi)存能力的系統(tǒng)來說,內(nèi)存碎片問題通常可能并不會和我們想象的那樣嚴重,原因就在于分配的內(nèi)存只需要在虛擬地址空間上連續(xù)而不必在物理內(nèi)存上也連續(xù),假定我們在虛擬內(nèi)存地址空間需要存放“aabbccdd”這樣的字符串,在虛擬地址空間上看這是連續(xù)的就像這樣:
但在物理內(nèi)存上可能是這樣存放的:
可以看到,利用虛擬內(nèi)存我們可以更加充分靈活的利用“邊邊角角”的物理內(nèi)存,從而減少內(nèi)存碎片帶來的影響。
如果你的程序需要重復(fù)申請很多對象/數(shù)據(jù)/結(jié)構(gòu)體,并在最后一次性全部釋放,那么內(nèi)存池是一個避免內(nèi)存碎片不錯的選擇,原理在于盡管從內(nèi)存池的角度看會有碎片,但當我們以內(nèi)存池大小為單位從堆區(qū)中申請釋放內(nèi)存時,這種碎片將不復(fù)存在。
內(nèi)存泄漏帶來的問題
在現(xiàn)代操作系統(tǒng)中除非你的程序運行時間足夠長或者申請的內(nèi)存足夠快足夠多否則內(nèi)存泄漏可能并不是什么大問題,你甚至可能都察覺不出來有內(nèi)存泄漏,因為當進程運行結(jié)束后其占據(jù)的內(nèi)存會被操作系統(tǒng)收回,在這種情況下你可能不必過于關(guān)心這個問題,但對于長時間運行的服務(wù)器端程序、數(shù)據(jù)庫程序、操作系統(tǒng)等,內(nèi)存泄漏就屬于比較嚴重的問題了,因為這些程序必須時刻在線,任何微小的內(nèi)存泄漏在時間的加持下都會非常明顯。
內(nèi)存持續(xù)泄漏會發(fā)生什么?
如果內(nèi)存持續(xù)泄漏那么你的電腦可能會爆炸。。。這。。。當然是不可能的。
你的系統(tǒng)會慢到炸是有可能的。
內(nèi)存的申請速度會對系統(tǒng)性能產(chǎn)生很大的影響,當系統(tǒng)內(nèi)存不足時,內(nèi)存分配器找到一塊滿足要求的空閑內(nèi)存塊將更加困難耗時更多,當程序消耗的內(nèi)存超過物理內(nèi)存大小時虛擬內(nèi)存系統(tǒng)(如果有的話)開始發(fā)揮作用,將進程地址空間中不常用的一部分swap出去,此時系統(tǒng)性能將快速下降,表現(xiàn)出來的就是程序員運行變慢、卡頓。
當然,根據(jù)系統(tǒng)配置,像Linux系統(tǒng),可能會將消耗內(nèi)存很多的進程kill掉,這就是Out of Memory killer,簡稱oom killer。
內(nèi)存泄漏檢測工具
不像程序崩潰Core dump,這類問題通過debug通常能獲取一些線索,但內(nèi)存泄漏問題就沒那么直接了,尤其對于C/C++程序來說,這時我們將不得不借助必要的工具。
往期推薦
虛幻引擎5上的《黑客帝國》全新體驗,愛了愛了
低代碼發(fā)展專訪系列之七:低代碼的火爆需要不一樣的聲音么?
Log4j 第三次發(fā)布漏洞補丁,漏洞或?qū)㈤L存
5G專網(wǎng),路在何方?
點分享
點收藏
點點贊
點在看
總結(jié)
以上是生活随笔為你收集整理的彻底理解内存泄漏,memory leak的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 明明还有大量内存,为啥报错“无法分配内存
- 下一篇: 为什么服务端程序都需要先 listen