JVM如何判断是否回收对象

一、对象标记算法

1.引用计数法

给对象中添加一个引用计数器,每当有一个地方引用它,计数器就加 1;当引用失效,计数器就减 1;任何时候计数器为 0 的对象就是不可能再被使用的。

这个方法实现简单,效率高,但是目前主流的虚拟机中并没有选择这个算法来管理内存,其最主要的原因是它很难解决对象之间相互循环引用的问题。 所谓对象之间的相互引用问题,比如:objA 和 objB互相引用,除了对象 objA 和 objB 相互引用着对方之外,这两个对象之间再无任何引用。但是他们因为互相引用对方,导致它们的引用计数器都不为 0,于是引用计数算法无法通知 GC 回收器回收他们。


2.可达性分析算法

2.1概念:

这个算法的基本思想就是通过一系列的称为 “GC Roots” 的对象作为起点,从这些节点开始向下搜索,节点所走过的路径称为引用链,当一个对象到 GC Roots 没有任何引用链相连的话,则证明此对象是不可用的。

在这里插入图片描述
JVM 会起一个线程从所有的 GC Roots 开始往下遍历,当遍历完之后如果发现有一些对象不可到达,那么就认为这些对象已经没有用了,需要被回收。

2.2可以作为GC Roots 的对象:

  • 虚拟机栈中的引用的对象
  • 全局的静态的对象,也就是使用了 static 关键字
  • 常量引用,就是使用了 static final 关键字
  • 本地方法栈中引用的对象

二、判断对象生与死

宣告一个对象死亡,至少要经历两次标记

1、第一次标记
  如果对象进行可达性分析算法之后没发现与 GC Roots 相连的引用链,那它将会第一次标记并且进行一次筛选。

筛选条件:判断此对象是否有必要执行 finalize () 方法。

筛选结果:当对象没有覆盖 finalize () 方法、或者 finalize () 方法已经被 JVM 执行过,则判定为可回收对象。如果对象有必要执行 finalize () 方法,则被放入 F-Queue 队列中。稍后在 JVM 自动建立、低优先级的 Finalizer 线程(可能多个线程)中触发这个方法;

2、第二次标记
  GC 对 F-Queue 队列中的对象进行二次标记。

如果对象在 finalize () 方法中重新与引用链上的任何一个对象建立了关联,那么二次标记时则会将它移出 “即将回收” 集合。如果此时对象还没成功逃脱,那么只能被回收了。

3、finalize () 方法
  finalize () 是 Object 类的一个方法、一个对象的 finalize () 方法只会被系统自动调用一次,经过 finalize () 方法逃脱死亡的对象,第二次不会再调用;

特别说明:并不提倡在程序中调用 finalize () 来进行自救。建议忘掉 Java 程序中该方法的存在。因为它执行的时间不确定,甚至是否被执行也不确定(Java 程序的不正常退出),而且运行代价高昂,无法保证各个对象的调用顺序(甚至有不同线程中调用)。

发布了147 篇原创文章 · 获赞 835 · 访问量 27万+

猜你喜欢

转载自blog.csdn.net/qq_33945246/article/details/103902340