@@ -906,17 +906,92 @@ JVM 在我们创建 Java 对象的时候去分配新内存,并使用 GC 算法
906
906
907
907
### 对象的死亡过程?
908
908
909
- 1. 第一次标记
909
+ 在 Java 中,对象被垃圾回收器( Garbage Collector , GC )判定为“死亡”并回收内存的过程,涉及 ** 两次标记 ** 和潜在的 ** 自救机会 ** (通过 `finalize()` 方法)
910
910
911
- 对象在进行可达性分析后发现没有与 GC Roots 相连接的引用链,那它将会被第一次标记。
911
+ ** 一、第一次标记:可达性分析 **
912
912
913
- 2. 第二次标记
913
+ 1. ** 触发条件 ** :当 JVM 开始垃圾回收时,首先通过 ** 可达性分析算法( Reachability Analysis ) ** 判断对象是否存活。
914
914
915
- 假如对象没有覆盖 finalize 方法,或者 finalize 方法已经被虚拟机调用过,那么不执行 finalize 方法。
916
- 如果有必要执行 finalize 方法,那么该对象将会被放置在一个名为 F - Queue 的队列之中,并在稍后由一条由虚拟机自动建立的、低调度优先级的 Finalizer 线程去执行它们的 finalize 方法。
915
+ 2. ** GC Roots 的引用链**
917
916
918
- finalize 方法是对象逃脱死亡命运的最后一次机会,稍后收集器将对 F - Queue 中的对象进行第二次小规模的标记,如果对象要在 finalize 中成功拯救自己,只要重新与引用链上的任何一个对象建立关联即可。
919
- 如果对象这时候还没有逃脱,那基本上它就真的要被回收了。
917
+ - GC Roots 对象包括:
918
+ - 虚拟机栈(栈帧中的局部变量表)引用的对象。
919
+ - 方法区中静态变量引用的对象。
920
+ - 方法区中常量引用的对象(如字符串常量池)。
921
+ - JNI (Java Native Interface )引用的本地方法栈对象。
922
+
923
+ - ** 遍历过程** :从 GC Roots 出发,递归遍历所有引用链。未被遍历到的对象即为不可达对象。
924
+
925
+ 3. ** 第一次标记结果**
926
+
927
+ - ** 存活对象** :与 GC Roots 存在引用链,继续保留。
928
+
929
+ - ** 待回收对象** :不可达,被标记为“可回收”,进入第二次标记阶段。
930
+
931
+ ** 二、第二次标记:finalize() 方法的自救机会**
932
+
933
+ 1. ** 筛选条件**
934
+
935
+ - 若对象未覆盖 `finalize()` 方法,或 `finalize()` 已被调用过,则直接判定为死亡,无需进入队列。
936
+
937
+ - 若对象覆盖了 `finalize()` 且未被调用过,则将其加入 ** F - Queue 队列** ,进入自救流程。
938
+
939
+ 2. ** F - Queue 与 Finalizer 线程**
940
+
941
+ - ** F - Queue ** :一个低优先级的队列,存放待执行 `finalize()` 的对象。
942
+
943
+ - Finalizer 线程:JVM 创建的守护线程,负责异步执行队列中对象的 `finalize()` 方法。
944
+ - ** 注意** :`finalize()` 的执行不保证完成(如线程优先级低或方法死循环)。
945
+
946
+ 3. ** 自救机制**
947
+
948
+ 在 `finalize()` 方法中,对象可通过重新与 GC Roots 引用链建立关联来自救:
949
+
950
+ ```java
951
+ public class Zombie {
952
+ private static Zombie SAVE_HOOK ;
953
+
954
+ @Override
955
+ protected void finalize () throws Throwable {
956
+ super . finalize();
957
+ System . out. println(" finalize() 执行,对象自救" );
958
+ SAVE_HOOK = this ; // 重新建立与 GC Roots 的关联
959
+ }
960
+
961
+ public static void main (String [] args ) throws Exception {
962
+ SAVE_HOOK = new Zombie ();
963
+ SAVE_HOOK = null ; // 断开引用,触发 GC
964
+ System . gc();
965
+ Thread . sleep(500 ); // 等待 Finalizer 线程执行 finalize()
966
+ if (SAVE_HOOK != null ) {
967
+ System . out. println(" 对象存活" );
968
+ } else {
969
+ System . out. println(" 对象被回收" );
970
+ }
971
+ }
972
+ }
973
+
974
+
975
+ ---- - 输出结果
976
+ finalize() 执行,对象自救
977
+ 对象存活
978
+ ```
979
+
980
+ - 关键点:
981
+ - 对象通过 `finalize()` 将 `this ` 赋值给静态变量 `SAVE_HOOK `,重新建立与 GC Roots 的引用链。
982
+ - 自救仅生效一次,第二次 GC 时对象仍会被回收。
983
+
984
+ ** 三、对象回收的最终判定**
985
+
986
+ 1. ** 第二次标记结果**
987
+
988
+ - ** 自救成功** :对象重新与引用链关联,移出待回收集合。
989
+
990
+ - ** 自救失败** :对象仍不可达,被标记为“死亡”,等待内存回收。
991
+
992
+ 2. ** 回收内存**
993
+
994
+ 根据垃圾收集算法(如标记- 清除、复制、标记- 整理等),将死亡对象的内存回收。
920
995
921
996
922
997
0 commit comments