对象已死吗?
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了对象已死吗?相关的知识,希望对你有一定的参考价值。
为什么要讨论这个问题呢?
在堆里面存放着java世界中几乎所有的对象实例,垃圾收集器在对堆进行回收前,第一件事情就是要确定这些对象之中哪些还“存活”着,哪些已经“死去”(即不可能再被任何途径使用的对象)。
下面有几种算法判断对象是否已经死去。(注意是判断对象是否可回收的算法,并不是回收算法)
1.引用计数算法:给对象添加一个引用计数器,每当有一个地方引用它时,计数器值就加1;当引用失效时,计数器值就减1;任何时刻计数器为0的对象就是不可能再被使用的。
主流的java虚拟机里面没有选用这个算法来管理内存,主要原因是它很难解决对象之间相互循环引用的问题。
2.可达性分析算法
从字面理解此算法,即判断某个对象是否可达。 这个算法的基本思路就是通过一系列的称为“GC Roots”的对象作为起始点,从这些节点开始向下搜索,搜索所走过的路径称为引用链,当一个对象到GC Roots没有任何引用链相连时,则证明此对象是不可用的。
3.再谈引用!
无论是通过引用计数算法判断对象的引用数量,还是通过可达性算法判断对象的引用链是否可达,判定对象是否存活都与“引用”有关。 但引用的定义太纯粹,
C c=new C(); c引用着新创建的对象,在这种情况下看来一个对象好像只有被引用或没有被引用状态,对于如何描述一些“食之无味,弃之可惜”的对象就显得无能为力了。我们希望能描述这样一类对象:当内存空间还够时,则能保留在内存之中;如果内存空间在进行垃圾收集后还是非常紧张,则可以抛弃这些对象。很多系统的缓存功能都符合这样的场景。
在jdk1.2之后,java对引用的概念进行了扩充,将引用分为强引用,软引用,弱引用,虚引用 4种。这四种引用强度依次逐渐减弱。
4.生存还是死亡
即使在可达性分析算法中的不可达的对象,也并非是“非死不可”的,这个时候它们暂时进入“缓刑”阶段。要真正宣告死亡需要经历两次标记:如果对象在进行可达性分析后没有与GC Roots相连接的引用链,那它将会被第一次标记并且进行一次筛选,筛选条件是此对象是否有必要执行finalize()方法。当对象没有覆盖finalize()方法,或者finalize()方法已经被虚拟机调用过,这两种情况都没必要执行finalize()方法。
如果这个对象被判定为有必要执行finalize()方法,那么这个对象会被放置在一个叫做F-Queue的队列中。并在稍后由一个由虚拟机自动建立的,低优先级的Finalizer线程去执行它。这里所谓的“执行”是指虚拟机会触发这个方法,注意如果一个对象的finalize()方法执行缓慢,或者发生了死循环,将可能导致队列中其他对象处于等待,导致整个内存回收系统崩溃。finalize()方法是对象逃脱死亡命运的最后一次机会,稍后GC将会对F-Queue中的对象进行第二次小规模标记。
5.回收方法区
永久代的垃圾收集主要回收两部分内容:废弃常量和无用的类。废弃常量即无引用指向的常量。而无用类则需满足3个条件:
该类所有的实例都已经被回收,也就是java堆中不存在该类的任何实例。
加载该类的ClassLoader已经被回收
该类对应的java.lang.Class对象没有任何地方被引用,无法在任何地方通过反射访问该类的方法。
满足这三个条件的无用类进行回收,这里说的仅仅是“可以”,是否对类进行回收,HotSpot虚拟机提供了参数控制。
以上是关于对象已死吗?的主要内容,如果未能解决你的问题,请参考以下文章