徹底理解內存泄漏,Memory leak
大家好,我是小風哥,今天和大家聊一聊內存泄漏這個話題。
我之前寫過好幾篇關于內存的文章,在這些文章講到內存申請時我很喜歡用停車場來做類比,內存申請就好比去停車場找停車位,找到停車位后你就可以把車停在這里。
從這個類比看什么是內存泄漏呢?內存泄漏看上去是停車場的車輛只進不出導致最終找不到停車位,從程序員的角度看就是內存只申請取不釋放,如果你去問,可能有不少人認為內存泄漏就是這么回事。
然而這其實是不全面的。
申請過多內存
首先內存只申請不釋放未必就是內存泄漏,有可能是你的程序的確需要申請很多內存,這是正常的,然而如果是bug導致申請了很多內存,這就是內存泄漏了,或者也有人將其稱為space leak,意思是申請的內存超過了正常所需;不管是有意無意,總之在這種情況下你依然保持對這些內存的引用,因此你總可以找到這些內存并刪除它們,就看你刪不刪。
有很多情況會導致這一問題,像重復使用的某個結構體/對象,當再次復用時沒有清理上一次使用遺留的數據、系統中存在cache,但cache的過期策略設置不得當等等。
內存無法刪除
另一類比較有趣的內存泄漏是說你申請了一些內存,但最終卻沒有什么指向它們:
- void memory_leak() {
- char* mem = (char*)malloc(1024);
- // just return
- }
在這段代碼中我們申請了1k內存,然而當memory_leak函數返回后你就再也不知道這段內存到底在哪里了!
用停車場的示例來說就是有些司機太過土豪,家里的車太多以至于把將車放在停車場這件事忘掉了,導致這些車根本就不會有人再開走,因此白白浪費停車位,并導致可用車位越來越少,而對于編程來說就是粗心大意的程序員申請了一些內存后最終“忘掉”了,再也不會有什么東西(變量/指針)指向這些內存,因此在這種情況下你沒有辦法再找到這些內存并將其刪除。
內存碎片
這也算的上是一類特殊的內存泄漏,用停車場的例子來說就是兩個停車位中間停靠了一輛小型老年代步車,導致盡管這兩個停車位剩余的空間足夠大但又恰好都沒有辦法再停靠一輛小汽車。
假定我們系統中寶貴的內存大小只有8字節,其中有兩個字節已經分配出去了,就像這樣:
現在,系統中空閑的內存是6字節,下一次的內存申請需要分配5字節,糟糕,我們已經沒有辦法再找到連續的5個字節大小的內存空間了,盡管全部空間的內存還有6字節,這就是所謂的內存碎片問題。
而對于內存分配器來說如果出現這種情況那么將不得不借助操作系統的幫助來擴大堆區,因此看起來我們的程序占據的內存越來越多,盡管實際上程序可能并不需要那么多內存,僅僅是因為內存碎片的原因導致一部分內存無法被再次被利用起來。
然而對于現代操作系統尤其具備虛擬內存能力的系統來說,內存碎片問題通常可能并不會和我們想象的那樣嚴重,原因就在于分配的內存只需要在虛擬地址空間上連續而不必在物理內存上也連續,假定我們在虛擬內存地址空間需要存放“aabbccdd”這樣的字符串,在虛擬地址空間上看這是連續的就像這樣:
但在物理內存上可能是這樣存放的:
可以看到,利用虛擬內存我們可以更加充分靈活的利用“邊邊角角”的物理內存,從而減少內存碎片帶來的影響。
關于虛擬內存更詳細的講解你可以參考《深入理解操作系統》虛擬內存一章,關于公眾號“碼農的荒島求生”并回復“操作系統”即可。
如果你的程序需要重復申請很多對象/數據/結構體,并在最后一次性全部釋放,那么內存池是一個避免內存碎片不錯的選擇,原理在于盡管從內存池的角度看會有碎片,但當我們以內存池大小為單位從堆區中申請釋放內存時,這種碎片將不復存在。
關于內存池你可以參考這篇《高性能服務器內存池是如何實現的》。
內存泄漏帶來的問題
在現代操作系統中除非你的程序運行時間足夠長或者申請的內存足夠快足夠多否則內存泄漏可能并不是什么大問題,你甚至可能都察覺不出來有內存泄漏,因為當進程運行結束后其占據的內存會被操作系統收回,在這種情況下你可能不必過于關心這個問題,但對于長時間運行的服務器端程序、數據庫程序、操作系統等,內存泄漏就屬于比較嚴重的問題了,因為這些程序必須時刻在線,任何微小的內存泄漏在時間的加持下都會非常明顯。
內存持續泄漏會發生什么?
如果內存持續泄漏那么你的電腦可能會爆炸。。。這。。。當然是不可能的。
你的系統會慢到炸是有可能的。
內存的申請速度會對系統性能產生很大的影響,當系統內存不足時,內存分配器找到一塊滿足要求的空閑內存塊將更加困難耗時更多,當程序消耗的內存超過物理內存大小時虛擬內存系統(如果有的話)開始發揮作用,將進程地址空間中不常用的一部分swap出去,此時系統性能將快速下降,表現出來的就是程序員運行變慢、卡頓。
當然,根據系統配置,像Linux系統,可能會將消耗內存很多的進程kill掉,這就是Out of Memory killer,簡稱oom killer。
內存泄漏檢測工具
不像程序崩潰Core dump,這類問題通過debug通常能獲取一些線索,但內存泄漏問題就沒那么直接了,尤其對于C/C++程序來說,這時我們將不得不借助必要的工具。
那么我們該利用什么的工具來解決內存泄漏問題呢?下一篇文章將給你答案。
這個公眾號里所有的文章都已經匯總在了Github上,地址https://github.com/xfenglu/everycodershouldknow ,你也可以點擊左下方“閱讀原文”直達,歡迎訪問,求star,哈哈。
本文轉載自微信公眾號「碼農的荒島求生」,可以通過以下二維碼關注。轉載本文請聯系碼農的荒島求生技術公眾號。