如何判断对象可以被回收

jvm是如何判断对象可以被回收的?

方法一:引用计数法

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

  此方法存在的局限性:不能解决对象之间相互引用的问题。例如:

  

 

   

 

  如上图所示,栈中引用了堆中对象objA和objB,此时objA和objB的引用计数器都加1;而且把objA赋值给objB的成员变量,objB赋值给objA的成员变量,也就是说objA和objB之间存在引用,此时objA和objB的引用计数器都再加1变成2。而当栈中对objA和objB的引用失效了之后,此时objA和objB实际上已经是无用对象了,但是objA和objB的引用计数器也都只是减1尚且不为0,因此objA和objB两个对象都不会被回收。任然占用堆的内存。这样的情况多了就可能出现内存泄漏问题。

方法二:可达性分析算法

  通过一系列的称为“GC Roots”的对象作为起始点,从这些节点开始向下搜索,搜索所走过的路径称为引用链(Reference Chain),当一个对象到GC Roots没有任何引用链相连(用图论的话来说,就是从GC Roots到这个对象不可达)时,则证明此对象是不可用的。

  

 

   

  在Java语言中,可作为GC Roots的对象包括下面几种:

    虚拟机栈(栈帧中的本地变量表)中引用的对象。

    方法区中类静态属性引用的对象。

    方法区中常量引用的对象。

    本地方法栈中JNI(即一般说的Native方法)引用的对象

方法三:

  常见引用类型:

    强引用:普通的变量引用

    软引用:将对象用SoftReference软引用类型的对象包裹,正常情况不会被回收,但是GC做完后发现释不出空间存放新的对象,则会把这些软引用的对象回收掉。软引用可用来实现对内存敏感度不高的高速缓存。public static SoftReference<User> user = new SoftReference<User>(new User());

    弱引用:将对象用WeakReference弱引用类型的对象包裹,弱引用跟没有引用差不多,GC会直接回收掉,很少用。

    public static WeakReference<User> user = new WeakReference<User>(new User());

    虚引用:虚引用也成为幽灵引用或幻影引用,它是最弱的一种引用,几乎不用。

方法四:finalize()方法最终判定对象是否存活

  即使在可达性分析算法中不可达的对象,也并非是“非死不可”de ,这时候它们暂时处于“缓刑”阶段,要真正宣告一个对象死亡,至少要经历再次标记过程。

  标记的前提是对象在进行可达性分析后发现没有与GC Roots相连接的引用链。

  1、第一次标记并进行一次筛选:

    对象没有覆盖finalize()方法,对象将直接被回收。

  2、第二次标记:

    如果这个对象覆盖了finalize()方法,只要重新与引用链上的任何一个对象建立关联即可。

PS:如何判断一个类是无用的类

  类需要同时满足下面3个条件才能算是无用的类:

  1、该类所有的实例都已经被回收,也就是堆中不存在该类的任何实例。

  2、加载该类的ClassLoader已经被回收。

  3、该类对应的java.lang.Class对象没有任何地方呗引用,无法在任何地方通过反射访问该类的方法。

posted @ 2020-03-23 16:04  城为唯一  阅读(1075)  评论(0编辑  收藏  举报