Garbage Collection 垃圾收集 java
Java中,GC的對象是堆空間和永久區(若是對Java內存區域不太瞭解,請查看Java內存區域) 算法
老牌垃圾回收算法
經過引用計算來回收垃圾 ide
使用者: 性能
引用計數器的實現很簡單,對於一個對象A,只要有任何一個對象引用了A,則A的引用計數器就加1,當引用失效時,引用計數器就減1。只要對象A的引用計數器的值爲0,則對象A就不可能再被使用。 優化
因此當一個對象的引用數量爲0,就意味着沒有人引用了這個對象,就能夠將這個對象GC掉。 this
引用計數法的問題: spa
從上圖能夠看出,右邊的3個對象,最後的引用計數都是1,可是都不被根對象所引用,三個垃圾對象循環引用,致使都沒法被回收。 .net
這裏要注意的是,引用計數法在Java中沒有采用。 線程
複製算法的問題:空間浪費,只能使用一半空間 code
經過整合標記清理思想來使得空間不怎麼浪費
中間那塊就是複製算法的核心區域,兩塊區域相同大小的空間。
具體步驟是:
1. 在最上面那塊大的區域產生新對象。
2. 大對象不太適合在複製空間,由於複製空間的容量是有限的,因此須要一個大的空間作擔保,因此讓老年代作擔保。這樣產生的大對象直接進入老年代。
3. 每一次GC,對象的年齡就會+1,一個對象在幾回GC後仍然沒有被回收,則這個對象就是一個老年對象。老年對象是一個長期被引用的對象,老年對象將被放入老年代。
4. 步驟1中產生的小對象,將進入到複製空間。原先複製空間中的新對象也將被複制到另外一塊複製空間
5. 清空垃圾對象
-XX:+PrintGCDetails的輸出
根據-XX:+PrintGCDetails的輸出,咱們能夠看到
一個堆分爲new generation(新生代) , tenured generation(老年代)和compacting perm gen。
而new generation分爲eden space,from space(有些地方稱爲s0和s1,表示倖存代) , to space。
eden space就是上面那種圖中,對象產生的地方。
from space和to space是兩塊大小同樣的區域,是上圖中的複製空間。
new generation的可用總空間就是eden space+一塊複製空間(另外一塊不算),可是根據new generation的地址訪問能夠算出是eden space + 兩塊複製空間區域,因此複製算法浪費了一部分空間。
依據對象的存活週期進行分類,短命對象歸爲新生代,長命對象歸爲老年代。
根據不一樣代的特色,選取合適的收集算法
進入老年代的對象有兩種狀況:
1. 新生代空間不夠,老年代作擔保存放一些大對象
2. 某些對象屢次GC後仍然存在,進入老年代。
老年代的大多數對象都是第2種狀況,因此老年代的對象的生命週期比較長,GC的發生也比較少,會有大量對象存活,因此不用複製算法,而改成標記清理或者標記壓縮。全部的算法,須要可以識別一個垃圾對象,所以須要給出一個可觸及性的定義
可觸及的
public class CanReliveObj { public static CanReliveObj obj; @Override protected void finalize() throws Throwable { super.finalize(); System.out.println("CanReliveObj finalize called"); obj = this; } @Override public String toString() { return "I am CanReliveObj"; } public static void main(String[] args) throws InterruptedException { obj = new CanReliveObj(); obj = null; // 可復活 System.gc(); Thread.sleep(1000); if (obj == null) { System.out.println("obj 是 null"); } else { System.out.println("obj 可用"); } System.out.println("第二次gc"); obj = null; // 不可復活 System.gc(); Thread.sleep(1000); if (obj == null) { System.out.println("obj 是 null"); } else { System.out.println("obj 可用"); } } }
輸出:
CanReliveObj finalize called obj 可用 第二次gc obj 是 null通常咱們認爲,對象賦值null後,對象就能夠被GC了,在上述實例中,在finalize中,又將obj=this,使對象復活。由於finalize只能調用一次,因此第二次GC時,obj被回收。
所以對於finalize會有這樣的建議:
全局停頓,全部Java代碼中止,native代碼能夠執行,但不能和JVM交互
多半因爲GC引發,固然Dump線程、死鎖檢查、堆Dump都有可能引發Stop-The-World
GC時爲何會有全局停頓?
類比在聚會時打掃房間,聚會時很亂,又有新的垃圾產生,房間永遠打掃不乾淨,只有讓你們中止活動了,才能將房間打掃乾淨。
危害 長時間服務中止,沒有響應
遇到HA系統,可能引發主備切換,嚴重危害生產環境。
新生代的GC(Minor GC),停頓時間比較短
老年代的GC(Full GC),停頓時間可能比較長