(2)基本思路
① 以根对象集合为起始点,按照从上至下的方式搜索被根对象集合所连接的目标对象是否可达
② 使用可达性分析算法后,内存中的存活对象都会被根对象集合直接或间接连接着,搜索走过的路径称为引用链
③ 目标对象没有被任何引用链相连,则是不可达的,意味着该对象已经死亡,可以标记为垃圾对象
④ 只有被根对象集合直接或间接连接的对象才是存活对象
(3)GC Roots包括以下几类元素:
① 虚拟机栈中引用的对象,例如各个线程被调用的方法中使用到的参数、局部变量等
② 本地方法栈内JNT(通常说的本地方法)引用的对象
③ 方法区中类静态属性引用的对象,例如Java类的引用类静态变量
④ 方法区中常量引用的对象,例如字符串常量池里的引用
⑤ 所有被同步锁持有的对象
⑥ Java虚拟机内部的引用,例如基本数据类型对应的Class对象,一些常驻的异常对象,系统类加载器
⑦ 反映Java虚拟机内部情况的JMXBean、JVMTI中注册的回调、本地代码缓存等
3. 对象的finalization机制
(1)Java语言提供了对象终止机制来允许开发人员提供对象被销毁之前的自定义处理逻辑,当垃圾回收器发现灭有引用指向一个对象,就会先调用这个对象的finalize()方法,这个方法运行在子类中被重写,用于在对象被回收时进行资源释放
(2)永远不要主动调用对象的finalize()方法,应该交给垃圾回收机制调用,理由包括以下三点:
① finalize()时可能会导致对象复活
② finalize()方法的执行时间是没有保障的,完全有GC线程决定,若没有发生GC,则finalize()就没有执行机会
③ 一个糟糕的finalize()会严重影响GC的性能
(3)由于finalize()方法的存在,虚拟机中的对象一般处于三种状态
① 可触及的:从根节点开始,可以达到这个对象
② 可复活的:对象的所有引用都被释放,但是对象有可能在finalize()中复活
③ 不可触及的:对象的finalize()方法被调用并且没有被复活,finalize()方法只会被调用一次
(4)判断一个对象是否可回收,至少要建立两次标记过程
① 如果对象到GC Roots没有引用链,则进行第一次标记
② 判断此对象是否有必要执行finalize()方法
如果对象没有重写finalize()方法,或者finalize()以及被虚拟机调用过,则对象被判断为不可触及
如果对象重写了finalize(),且还未被执行,那么对象会被插入到F-Queue队列中,由虚拟机自动创建、优先级低的Finalizer线程触发其finalize()方法执行
finalize()方法是对象逃脱死亡的最后机会,GC会对F-Queue队列中的对象进行第二次标记,如果对象在finalize()中与引用链上的任何一个对象建立联系,那么对象会被移出即将回收集合变成复活状态,之后对象会再次出现没有引用存在的情况,由于finalize()已经被调用过,所以对象会直接变成不可触及状态