垃圾回收(garbage collection)介紹
阿新 • • 發佈:2019-01-08
垃圾回收用來實現記憶體的自動管理(automatic management),區別於人工管理(manual management)。人工管理記憶體容易出現的問題:
1)懸垂指標,dangling pointer
2)重複回收,Double free
3)記憶體洩露,memory leak
歷史
垃圾回收的概念及技術由John McCarthy於1959年發明,應用於List語言中。1959年,電腦科學應該還處於探索、萌芽階段,但這位大神已經發明瞭垃圾回收,大神就是大神。
策略
目前的垃圾回收策略有兩種:
1)引用技術 reference counging
思路:給每個物件增加一個引用計數器。每增加一個隊物件的引用,計數器增加;較少引用,計數器減少;當計數器是0時,表示物件可以回收。
這種方式實現簡單,速度快,回收程式碼和程式程式碼執行同步;最大的問題是不能解決迴圈引用問題(cyclic reference)。
2)物件追中 object tracing
思路:儲存系統中所有已分配的物件,一些物件被稱為根(roots objects)。所有跟物件及從跟物件可達(reach)的物件被稱為活躍物件(active),剩餘的物件就是垃圾物件,可以進行回收。
實現較複雜,回收時機和執行時間不可控(回收程式碼和程式程式碼分開執行,回收程式碼會阻塞程式程式碼的執行),但可以解決迴圈引用問題。
每種策略都有系統採用:
採用引用計數的有:ios,python,COM,C++庫(auto_ptr等)
採用物件追蹤的有:Java, .Net, lisp等
演算法
主要介紹基於物件追蹤的演算法。
標記-清除法,mark-sweep
這個應該是由John McCarthy發明的。將垃圾回收分為兩個階段:
標記階段:找出所有active物件,從跟物件開始遍歷。所有active物件通過一個標誌位表示。
清除階段:遍歷所有物件,如果該物件不是active的,回收,釋放空間。
清除後的記憶體存在碎片問題(fragmentation)。
複製演算法,copying
也叫Cheney's algorithm, 由C.J. Cheney發明,大約在1970年。思路將記憶體分成大小相同的2個區:當一個區滿了後,對這個區執行垃圾回收。先執行標記階段找出所有活躍的物件,然後將所有活躍物件複製到另外一個記憶體區,當前記憶體區可以被整個回收。
這種方法解決了記憶體碎片問題,但是引入一個新問題,記憶體利用率只有一半。
分代演算法,generational
沒有找到具體的發明人。
將記憶體分成不同的區,每個區存放不同特點的物件,如按照物件的生命週期長短來劃分。每個區可以採用不同的方法進行回收。在目前的JVM實現中,都是採用這種分帶的演算法進行垃圾回收。
Oracle JVM中的分代:
http://www.oracle.com/technetwork/java/javase/gc-tuning-6-140523.html
上述3個演算法構成了整個垃圾回收的核心,當前的所有演算法都是基於上述三種方法產生。這三種方法本身都不是很複雜,但第一個想到這些方法的人還是非常偉大的。
衍生演算法
標記整理,mark-sweep-compact(也叫mark-compact)
這種方法是mark-sweep和copy演算法的結合。先執行標記階段找出所有活躍的物件,然後將所有活躍物件向記憶體區的起始點移動(rellocate),所有物件連續防止。最後一個活躍物件的後面的所有記憶體空間可以一次性釋放,這種方法即解決了記憶體碎片問題,又解決了記憶體利用率的問題。目前JVM中廣泛採用。
Oracle JVM中的GC
主要採用了3種演算法:分代,拷貝和標記整理。
對young(青年代)的回收,採用拷貝演算法。注意的是,記憶體並沒有分成2個大小相同的區,而是不等的兩個區eden和survivor,具體比例可以通過JVM引數設定。這個設計的依據是:絕大多數物件在GC後都會被回收,只有少量存活,所有survivor不必和eden一樣大。對young的回收在JVM中叫做minor GC(or young GC),因為空間較小,速度會比較快,也會比較頻繁。
對tenured(老年代)的回收,採用標記整理(mark-sweep-compact)演算法。回收過程中需要物件的移動過程,同時tenured的空間也會比較大,回收時間會比較長。jvm中對整個heap(包括young和tenured,perm永久區不屬於heap)的回收叫做full gc。minor GC可能會觸發full gc的執行。
按GC演算法的併發能力分:
序列收集 serial collector
單執行緒執行,效率高,但是不支援多核。
並行收集 parallel collector
多執行緒執行,支援多核,在多核處理器上效能高。
按與程式程式碼的執行關係:
stop the world
執行GC時,程式程式碼不能執行。
Concurrent
GC可以和程式程式碼同時執行,但不是完全的並行,也需要停止程式程式碼,但停止時間比較短。目前能支援併發的只有一種即Concurrent Mark-Sweep (CMS) Collector。
JVM中的GC可以按照上方方法歸類,每個GC都可以從上述幾個維度劃分。分代演算法,是否並行,是否可併發執行等。