对象已死吗?

   为什么要讨论这个问题呢?

  在堆里面存放着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虚拟机提供了参数控制。

 

posted @ 2016-03-02 00:23  张-晓  阅读(358)  评论(0编辑  收藏  举报