JVM 垃圾回收算法
來自: http://my.oschina.net/u/1041012/blog/616142
對象可觸及性算法
可觸及性算法是判斷對象是否死亡的最基本的算法。所謂死亡對象就是內存堆中不再使用的對象。
用于被GC回收的對象。
引用計數算法 Reference Counting
引用計數法是給對象中添加一個引用計數器,每當有一個地方引用它時,計數器加1,
當引用失效時,計數器減1;任何時候計算器都為0的對象就是不可觸及的對象。Reference Counting 判定效率高,實現簡單。
微軟的COM,ActionScript3,FlashPlayer3,Python 都采用Reference Counting來計算Java 語言中沒有采用這個算法的主要原因是,它難以解決循環引用的問題。
根搜索算法 GC Root Tracing
基本思路就是就是通過一系列名為 GC Root 的對象作為起始點,從這些節點開始向下搜索,
搜索走過的路勁作為引用鏈,當一個對象到GC Root 沒有任何引用鏈時,則證明此對象不可觸及
GC Root 包括以下幾種
虛擬機棧中的引用的對象
方法區中的類靜態屬性引用的對象
方法區中的常量引用的對象
本地方法棧中JNI的引用的對象。
垃圾回收算法
標記-清楚算法 Mark-Sweep
標記-清楚算法是最基本的算法,其算法分為兩個階段,標記階段和清除階段。
首先標記出所需要回收的對象,標記完成后統一收掉所有的被標記的對象。
他的缺點主要有兩個:
效率問題,標記和清除的效率都不高
空間問題,標記清除后會產生大量的碎片內存
復制算法 Copying
為了解決效率問題,復制算法將可用內存分為大小相等的兩塊,每次只用其中一塊。
當一塊內存用完了,就將還存活著的對象復制到另外一塊上面,然后把已用過的內存空間一次清理掉。內存分配不用考慮碎片等復雜情況,只要移動堆頂指針,實現簡單,運行高效。只是這種算法的代價是將內存縮小為原來的一半。
**
在實際應用中,不會簡單的把所有存活對象從一邊拷貝到另外一邊,經過優化,會把大對象放到老生代的內存區域中,這一動作其實就是內存分配擔保的一個動作(Handle Promotion)。
我們沒有辦法保證每次需要復制的內存對象 在另一塊區域一定夠,這時需要借一塊區域通常來說是老年代存放,在清理之后在放回去,或者說就長期放在老年代了。
**
標記-壓縮算法 Mark-Compact
標記-壓縮算法是 標記-清除算法的一種優化,標記過程仍然一樣,但后續步驟不是直接對可回收對象進行清理,而是讓所有存活的對象都向一端移動,然后直接清理掉端邊界以外的內存。
分代收集 General Collection
所謂分代收集其實是各種回收算法的綜合應用。根據對象的存活周期的不同將內存劃分為幾塊。一般是把Java堆分為新生代和老年代。
新生代中,每次垃圾收集時都要發現大批對象死去,只有少量存活,那就選用復制算法,只需付出少量存活對象的復制。
而老年代中因為對象的存活率高,沒有額外的空間對它進行分配擔保,就必須使用標記清理或者壓縮算法。