【Java 虚拟机原理】垃圾回收算法 ( 可达性分析算法 | GC Root 示例 | GC 回收前的两次标记 | finalize 方法示例 )
文章目錄
- 一、可達性分析算法
- 二、GC Root 示例
- 三、GC 回收前的兩次標記
- 四、finalize 方法示例
一、可達性分析算法
在 堆內存 中 , 存在一個 根對象 GC Root , GC Root 對象一般是如下幾種情況 :
- 線程棧 中的 棧幀 中的 局部變量表 中的 引用對象 ;
- 方法區 中的 靜態引用對象 ;
- 方法區 中的 常量引用對象 ;
- 本地方法棧 中的 JNI 中的 引用的對象 ;
根對象 GC Root 指向了 對象 1 ; 對象 1 又指向了 對象 2 , 對象 3 ; 對象 3 指向了 對象 4 ;
只要是 處于整個鏈條上的對象 , 都是 非垃圾對象 , 不能進行回收的對象 ;
不處于 引用鏈條 上的對象 , 就是 垃圾對象 ;
下圖中 , 紫色的是存活對象 , 白色的是可回收的 垃圾對象 ;
二、GC Root 示例
找出下面程序中的 GC Root 對象 ;
public class HelloWorld {public static HelloWorld mHelloWorld = new HelloWorld();public int add() {int a = 1;int b = 1;int c = a + b;return c;}public static void main(String[] args) {HelloWorld helloWorld = new HelloWorld();helloWorld.add();} }第 131313 行的 helloWorld 對象是 GC Root 對象 , 符合 " 線程棧 中的 棧幀 中的 局部變量表 中的 引用對象 " 條件 ;
helloWorld 對象中有其它引用對象 , 只要引用鏈條沒有斷 , 那么鏈條上的對象都是 非垃圾對象 ;
一旦執行了 helloWorld = null; 語句 , 那么該對象及以下的對象就沒有了引用鏈條 , 這個對象及之下的對象就都變成了 垃圾對象 ;
三、GC 回收前的兩次標記
當對象被 定義為垃圾對象后 , 并不會馬上被回收 , 只是判了個死緩 , 沒有真正執行垃圾回收 ;
當 GC Root 引用鏈斷開后 , 對象不可達 ;
JVM 會對這些 不可達對象 進行一次標記 , 然后執行一次篩選 , 執行該對象的 finalize 方法 ,
public class HelloWorld {@Overrideprotected void finalize() throws Throwable {super.finalize();} }finalize 方法是對象被 GC 垃圾回收之前 , 被調用的方法 , 該方法不能保證一定能執行完畢 , JVM 會給對象一個時間限制 , 在這個時間內執行 finalize 方法 , 重寫的該方法中不要執行很耗時的操作 ;
在對象的 finalize 方法中 , 如果不想被回收 , 可以再次添加一個引用鏈 , 讓 GC Root 對象引用自己 ;
之后 JVM 會對不可達對象 進行第二次標記 , 此時如果發現 該對象 仍然是垃圾對象 , 此時直接將該對象回收 ;
finalize 方法只會被調用一次 , JVM 對 對象第二次標記時 , 發現對象如果沒有被引用 , 直接回收 , 不再調用 finalize 方法 ;
四、finalize 方法示例
創建一個對象 , 賦值給變量 A , 然后將 A 置空 , 該對象就變成了垃圾對象 ;
在 finalize 方法中 , 對象嘗試自救 , 將自己賦值給 A , 這樣該對象又變成了 非垃圾對象 ;
調用 System.gc() 方法后 , 一般需要暫停幾秒 , 等待 finalize 方法調用 ;
這里將 A 兩次置空 , 第一次調用了 finalize 方法 , 自救成功 , 沒有被回收 ;
第二次置空后 , finalize 方法不再調用 , 被回收了 ;
代碼示例 :
public class HelloWorld {public static HelloWorld A;@Overrideprotected void finalize() throws Throwable {super.finalize();System.out.println("finalize 被調用");A = this;}public static void main(String[] args) throws InterruptedException {A = new HelloWorld();// 將 對象 變為垃圾對象A = null;// 進行垃圾回收System.gc();// 由于 gc 的優先級比較低// 等待 1000ms 看 finalize 是否被調用Thread.sleep(1000);// 本次 GC 調用之前// 先調用了 finalize 方法// 為對象添加了 GC Root 引用鏈// 該方法只會調用一次if (A == null) {System.out.println("對象被回收");} else {System.out.println("對象未被回收");}// 將 對象 變為垃圾對象A = null;// 進行垃圾回收System.gc();// 由于 gc 的優先級比較低// 等待 1000ms 看 finalize 是否被調用Thread.sleep(1000);// 本次調用 GC// 直接判斷對象是否有引用鏈// 不再調用 finalize 方法// 發現沒有引用鏈 , 直接回收if (A == null) {System.out.println("對象被回收");} else {System.out.println("對象未被回收");}} }執行結果 :
finalize 被調用 對象未被回收 對象被回收總結
以上是生活随笔為你收集整理的【Java 虚拟机原理】垃圾回收算法 ( 可达性分析算法 | GC Root 示例 | GC 回收前的两次标记 | finalize 方法示例 )的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【Java 虚拟机原理】垃圾回收算法 (
- 下一篇: 【Google Play】APK 扩展包