天天看點

深入了解JAVA虛拟機(二)垃圾收集與記憶體配置設定政策一.JAVA虛拟機垃圾回收機制二.垃圾回收算法三.垃圾回收的時間各類垃圾收集器:

一.JAVA虛拟機垃圾回收機制

1.判斷一個對象是否存活

1.1 引用計數算法:給對象中添加一個引用計數器,每當有引用它時,計數器值就加1;當引用失效時,計數器值就減1;任何時刻計數器為0的對象就是不可能再被使用。

1.2 可達性分析算法:在Java中,都是通過可達性分析來對象是否存活的(如果對象是死的,那麼它所占用的記憶體就是需要回收的)。可達性分析算法的基本思想就是通過一系列被稱為“GC Roots”的對象開始,從這些節點向下搜尋,搜尋走過的路線稱為引用鍊。當一個對象沒有在任何引用鍊上出現,則這個對象會被判定為不可用的(死的,可回收的)。

       在被可達性分析算法判定為不可用的對象,也并非是一定就是會被回收的,它們還會經曆一次篩選的過程,篩選的條件就是此對象是不是要執行finalize()方法,如果對象沒有覆寫finalize()方法或它的finalize()方法在上一次垃圾回收器工作時已經執行過了,則被判定為不用執行finalize()方法(對象會在這次回收中被回收),若判定為需要執行finalize()方法,則這個對象會被放置在一個F-Queue隊列中,稍後虛拟機會建立一個finalizer線程(低優先級)來觸發這個方法,但虛拟機不承諾會等它執行完這個方法。(也就是這個對象可能在執行finalize()方法時被回收了),如果在finalize()方法中,對象加入了任何一個引用鍊中,則這個對象在這次回收器工作時就不會被回收了。

       在Java中,有幾種可作為GC Roots對象:虛拟機棧(棧幀中的本地變量表)中引用對象。方法區中類靜态屬性和常量引用的對象和本地方法棧中JNI引用的對象;

二.垃圾回收算法

1.标記-清除(Mark-Sweep)算法

首先會利用前面的可達性分析算法标記出需要回收的對象,在标記完成後就統一回收所有被标記的對象,這個算法的缺點主要有:

•效率問題,在标記和清除兩個過程中效率都不高;

•空間問題,标記清除之後會産生大量的記憶體碎片,碎片太多,可能導緻在下次為大對象配置設定記憶體時,提前觸發一次垃圾回收動作;

2.複制算法(Coping)

将可用的記憶體分為兩塊,每次隻使用其中的一塊,這樣每次隻需要順序配置設定記憶體就可以,當一塊的記憶體用完後,就把還存活的對象複制到另一塊記憶體中去,然後對使用過的記憶體空間進行回收就可以了。(一般不會采用平均分成兩塊的方式,現代虛拟機一般會将記憶體分成一塊較大的Eden空間和兩塊較小的Survivor空間,每次使用Eden空間和一塊Survivor空間,回收時,将Eden空間和Survivors空間裡還存活的對象複制到另一塊沒有使用的Survivor空間中,然後清理掉用過的空間),一般會這種算法回收新生代的記憶體空間。

3.标記-整理(Mark-Compact)算法

先利用可達性分析算法标記需要回收的對象,然後就讓還存活的對象(出現在任何引用鍊中的對象)都向一端移動,然後清理掉端邊界外的記憶體。(一般用來回收老年代的對象)。

三.垃圾回收的時間

大多數情況下,對象優先在Eden區中配置設定(大對象直接在老年代配置設定),當Eden沒有足夠空間時,JVM就會發起一次Minor GC。在進行Minor GC 之前,JVM會檢查老年代最大可用的空間是否大于新生代所有對象的空間,如果成立,則Minor GC是安全的,否則,JVM就會去檢查HandlePromotionFailure設定值是否允許擔保失敗。如果允許擔保失敗,則會繼續檢查老年代最大可用空間是否大于曆次晉升到老年代對象的平均大小,如果是,則會嘗試進行Minor GC(若失敗,就會進行一次Full GC);否則就會改為進行一次Full GC。

各類垃圾收集器:

垃圾收集器:

    新生代:Serial收集器,ParNew收集器,Parallel Scavenge收集器

    老年代:CMS, Seral Old(MSC), Parallel Old收集器

    GI收集器

繼續閱讀