Java JVM(二):垃圾回收概念 與 GC 日誌
阿新 • • 發佈:2019-02-02
包括:
一. 垃圾回收基本概念
二. GC日誌
一. 垃圾回收基本概念
在JVM 中,最需要進行回收的地方就是JVM 方法區 和 JVM 堆。
1.1 可達性分析演算法
回收的時候,主要是根據可達性分析演算法。如果一個物件不可達,那麼就是可以回收的;如果一個物件可達,那麼這個物件就不會被回收。那麼,對於可達性分析演算法,它是通過一系列稱為 "GC Roots" 的物件作為起始點,當一個物件到GC Root 沒有任何引用鏈相接的時候,則證明這個物件不可用,即可以進行回收。如下圖:
那麼,結果是一開始如下圖確實有3個例項,但是在stu = null 之後,例項就沒有,已經被GC回收。所以說不是程式計數法來判斷是否回收:
從 Full GC 資訊可知,新生代可用的記憶體大小約為 18M,則新生代實際分配得到的記憶體空間約為 20M(為什麼是 20M? 請繼續看下面…)。老年代分得的記憶體大小約為 42M,堆的可用記憶體的大小約為 60M。可以計算出: 18432K ( 新生代可用空間 ) + 42112K ( 老年代空間 ) = 60544K ( 堆的可用空間 )
新生代約佔堆大小的 1/3,老年代約佔堆大小的 2/3。也可以看出,GC 對新生代的回收比較樂觀,而對老年代以及方法區的回收並不明顯或者說不及新生代。並且在這裡 Full GC 耗時是 Minor GC 的 22.89 倍。
一. 垃圾回收基本概念
二. GC日誌
一. 垃圾回收基本概念
在JVM 中,最需要進行回收的地方就是JVM 方法區 和 JVM 堆。
1.1 可達性分析演算法
回收的時候,主要是根據可達性分析演算法。如果一個物件不可達,那麼就是可以回收的;如果一個物件可達,那麼這個物件就不會被回收。那麼,對於可達性分析演算法,它是通過一系列稱為 "GC Roots" 的物件作為起始點,當一個物件到GC Root 沒有任何引用鏈相接的時候,則證明這個物件不可用,即可以進行回收。如下圖:
這個GC Root 物件可以是一些靜態的物件,Java方法的local變數或引數, native 方法引用的物件,活著的執行緒。
Ps:
有些資料認為 垃圾回收根據引用計數法,但是在本人的測試中結果是用可達性分析演算法。證明如下:
有如下程式(Student 物件1 -->Student物件2 -->Student物件3):
public class Test { public static void main(String[] args) throws InterruptedException { Student stu = new Student(new Student(new Student())); Thread.sleep(15 * 1000); stu = null; Thread.sleep(100 * 1000); } } class Student { private String name; private Student stu; public Student() {} public Student(Student stu){this.stu = stu;}; }
那麼,結果是一開始如下圖確實有3個例項,但是在stu = null 之後,例項就沒有,已經被GC回收。所以說不是程式計數法來判斷是否回收:
1.2 回收方式
回收方式會有多種,比如說標記-清除法;複製演算法;標記-整理法。
複製演算法:JVM 的堆記憶體會分為新生代和老年代,新生代主要就是採用複製演算法。複製演算法的主要概念是:把記憶體分為AB兩塊,每次只是使用其中一塊,當A記憶體使用完之後,就把A 中還存活的物件複製到另外一塊記憶體中去。這樣的有點就是不需要考慮記憶體碎片的問題。缺點就是記憶體減半,代價太高。但是在新生代的實際應用中,不會55分,而是按8:1:1 的比例,分為1個Eden區 和兩個Survivor 區域。這就是複製演算法。
標記整理法:JVM的老年代就是用 標記整理法,也就是說,當需要GC 的時候,會先標記,然後把存活的物件都移到一端。
二. GC日誌
圖1
圖2
從 Full GC 資訊可知,新生代可用的記憶體大小約為 18M,則新生代實際分配得到的記憶體空間約為 20M(為什麼是 20M? 請繼續看下面…)。老年代分得的記憶體大小約為 42M,堆的可用記憶體的大小約為 60M。可以計算出: 18432K ( 新生代可用空間 ) + 42112K ( 老年代空間 ) = 60544K ( 堆的可用空間 )
新生代約佔堆大小的 1/3,老年代約佔堆大小的 2/3。也可以看出,GC 對新生代的回收比較樂觀,而對老年代以及方法區的回收並不明顯或者說不及新生代。並且在這裡 Full GC 耗時是 Minor GC 的 22.89 倍。
總結:
- 主要回收場所:JVM方法區,JVM方法棧。
- 回收方式: 新生代(複製演算法),老年代(標記整理法)。
- 根據Young / Old 判斷是新生代還是老年代的 GC,然後就是給出 Young / Old ,整個堆記憶體 GC 前後的大小。