有些程序並不需要管理它們的動態內存的使用。當需要內存時,它們簡單地通過分配來獲得,從來不用擔心如何釋放它。這類程序包括編譯器和其他一些運行一段固定的(或有限的)時間然後終止的程序。當這種類型的程序終止時,所有內存會被自動回收。細心查驗每塊內存是否需要回收純屬浪費時間,因為它們不會再被使用。
其他程序的生存時間要長一點。有些工具如日歷管理器、郵件工具以及操作系統本事經常需要數日及至數周連續運行,並需要管理動態內存的分配和回收。由於C語言通常並不使用垃圾回收器(自動確認並回收不再使用的內存塊),這些C程序在使用malloc()和free()時不得不非常慎重。
堆經常會出現兩種類型的問題:
1.釋放或改寫仍在使用的內存(稱為:“內存損壞”)。
2.未釋放不再使用的內存(稱為:“內存洩露”)。
這是最難被調試發現的問題之一。如果每次已分配的內存塊不再使用而程序並不釋放它們,進程就會一邊分配越來越多的內存,一邊卻並不釋放不再使用的那部分內存。
避免內存洩露
每當調用malloc分配內存時,注意在以後要調用相應的free來釋放它。
如果不知道如何調用free與先前的malloc相對應,那麼很可能已經造成了內存洩露!
一種簡單的方法就是在可能的時候使用alloca()來分配動態內存,以避免上述情況。當離開調用alloca的函數時,它所分配的內存會被自動釋放。
顯然,這並不適用於那些比創建它們的函數生命期更長的結構。但如果對象的生命期在該函數結束前便已經終止,這種建立在堆棧上的動態內存分配是一種開銷很小的選擇。有些人不提倡使用alloca,因為它並不是以後總可移植的方法。如果處理器在硬件上不支持堆棧,alloca()就很難高效地實現。
我們使用“內存洩露”這個詞是因為一種稀有的資源正在被一個進程搾干。內存洩露的主要可見症狀就是罪魁進程的速度很減慢。原因是體積大的進程更有可能被系統換出,讓別的進程運行,而且大的進程在換進換出時花費的時間也更多。即使洩露的內存本省並不被引用,但它仍用可能存在於頁面中(內容自然是垃圾),這樣就增加了進程的工作頁數量,降低了性能。另外需要注意的一點是,內存洩露往往比忘記釋放的的數據結構要打,因為malloc()所分配的內存通常會圓整為下一個大於申請數量的2的整數次方(如申請212B,會圓整為256B)。在資源有限的情況下,即使引起內存洩露的進程並不運行,整個系統運行速度也會被拖慢。從理論上說,進程的大小有一個上限值,這在不同的操作系統中各不相同。在當前的SunOS版本中,進程的最大地址空間可以多達4GB。事實上,在進程所洩露的內存遠未達到這個數量時,磁盤的交換區早已消耗殆盡。
如何檢測內存洩露
觀察內存洩露是一個兩步驟的過程。首先,使用swap命令觀察還有多少可用的交換空間:
/usr/sbin/swap -s
total:17228K bytes allocated + 5396K reserved=22626K used,29548K available.
在一兩分鐘內鍵入該命令三到四次,看看可用的交換區是否在減少。還可以使用其他一些/usr/bin/*stat工具如netstat、vmstat等。如發現波段有內存被分配且從不釋放,一個可能的解釋就是有個進程出現了內存洩露。