記憶體篇之堆洩漏

2021-06-19 21:22:48 字數 1545 閱讀 9438

「堆洩漏」即常說的記憶體洩漏,是嵌入式軟體裡的常見問題,會導致軟體執行一段時間後記憶體耗盡。

什麼是」堆洩漏」?

記憶體分配和釋放的操作是程式設計師根據需要動態隨機發起,程式本身(或編譯工具)無法自動判斷某塊已分配的記憶體什麼時候不再被使用,必須由程式設計師自己手動呼叫free釋放,以便為其他程式騰出空間。而一旦程式設計師忘記釋放某塊記憶體,它就不能回到可用記憶體,系統總的可分配記憶體就隨之減少,這就是記憶體洩漏。注意這裡的記憶體特指堆(heap),只有堆記憶體才需要程式設計師自己控制分配和釋放。所以記憶體洩漏和堆洩漏是同一概念。

新手對洩漏這個詞往往感到不理解,不就是分配後忘記釋放,怎麼叫洩漏呢?叫記憶體丟失不是更通俗麼?

關於這點,可以打個比方,分配記憶體就是從銀行貸款,而釋放記憶體就是給銀行還錢。如果有人借了錢卻賴帳不還,那麼銀行可支配的錢就會減少,銀行總資產就被損失或洩漏。類似,堆是一塊固定大小記憶體,「借」給不同程式使用,如果某個程式只借不還,堆管理所能支配的記憶體就減少,因此記憶體洩漏是針對系統中總的可支配記憶體資源來說,而並不是物理記憶體真的丟失。從這個角度理解,leak絕對比lost更準確生動:一種資源在封閉系統中迴圈使用,如果部分資源無法回到迴圈,不正是洩漏到封閉系統之外了麼?

借錢不還的銀行客戶越來越多,最終銀行就會因為沒錢放貸周轉而破產。同樣發生記憶體洩漏,直接的表現就是軟體執行越來越慢,最終甚至因分不到記憶體而崩潰。(所以說一定要判斷malloc的返回值,不是每次都能從銀行借到錢滴)

洩漏原因及對策

所有老師都會強調malloc後一定要有free,但實際編寫複雜**時,記憶體洩漏幾乎不可避免。比如下面多分支退出,某分支忘記釋放已分配的記憶體,就導致洩漏:

void myfunc(int size)

…//using the string pointed by p;

free(p);}

無法完全避免記憶體洩漏,只能通過一些程式設計原則減少洩漏的概率:

1) 減少多分支退出而遺漏free,可用goto語句保證函式只有乙個退出點。

2) 保證在同一層上使用malloc/free對,也就是說不要在子函式中malloc,在外層主函式free。這種內存在不同層次分配釋放會使邏輯層次混亂,很容易導致記憶體洩漏。

char* allocstrfromheap(int len)

相反如果在主函式中malloc並使用記憶體,而在某子函式中釋放引數所指記憶體,可能導致主函式中出現野指標(後續)。

3)人工review**查詢記憶體洩漏很困難,可借助工具快速檢測,如boundchecker/pc-lint等都能通過自動掃瞄**找到記憶體洩漏。

隱式洩漏

是指某記憶體已使用完,明明可以早點free掉,卻非等到軟體退出前才釋放,俗稱「佔著xx不xx」,雖然程式最終釋放了所有記憶體,嚴格意義上沒有洩漏,但某些場合隱式洩露同樣會導致嚴重後果:比如某長期執行的伺服器程式,如果不斷分配而不及時釋放記憶體,最後系統很可能在執行中途就因堆記憶體耗盡而crash,因此記憶體使用過程中,不但要確保釋放記憶體,而且用完要盡快釋放,而不要全等到退出前釋放,以消除隱式洩漏,確保記憶體占用峰值不超過系統堆資源上限。

C 之記憶體洩漏篇

前段時間面試經常被問到記憶體洩漏。今天小總結一下 記憶體洩漏的發生是由於使用者在堆上分配了空間,但卻沒有釋放它。持續的記憶體洩漏最終將導致堆的耗盡,後繼的記憶體分配將會失敗。引發記憶體洩漏的原因是用new分配的記憶體沒有用delete釋放掉。如 可能在onpaint這樣的繪畫視窗的函式中分配了空間,...

記憶體洩漏之EventBus

專案中使用了eventbus之後,不停地出現報告關於eventbus記憶體洩漏的leaks 反覆檢查了 發現eventbus的註冊已經解綁都是正確的,一開始也覺得這個記憶體洩漏地莫名其妙。洩漏大概說的是,eventbus持有了某個activity或者fragment的物件,這個物件洩漏了。後面我梳理...

記憶體洩漏和記憶體溢位 記憶體洩漏和記憶體溢位

記憶體洩漏 是指申請的記憶體空間使用完畢之後未 一次記憶體洩露危害可以忽略,但若一直洩漏,無論有多少記憶體,遲早都會被占用光,最終導致程式crash。因此,開發中我們要盡量避免記憶體洩漏的出現 記憶體溢位 是指程式在申請記憶體時,沒有足夠的記憶體空間供其使用。通俗理解就是記憶體不夠用了,通常在執行大...