java_虚拟机

对象存活判定算法(可回收对象的判定)

2017-04-19  本文已影响64人  今有所思

概述

程序计数器、虚拟机栈、本地方法栈这些区域不需要过多考虑回收的问题,因为方法结束或者线程结束时,内存自然就跟着回收了。垃圾收集器关注的是堆和方法区中的垃圾

对象引用

Java中的垃圾回收一般是在Java堆中进行,因为堆中几乎存放了Java中所有的对象实例。谈到Java堆中的垃圾回收,自然要谈到引用。在JDK1.2之前,Java中的引用定义很很纯粹:如果reference类型的数据中存储的数值代表的是另外一块内存的起始地址,就称这块内存代表着一个引用。但在JDK1.2之后,Java对引用的概念进行了扩充,将其分为强引用(Strong Reference)、软引用(Soft Reference)、弱引用(Weak Reference)、虚引用(Phantom Reference)四种,引用强度依次减弱。

1. 引用计数算法(Reference Counting)

引用计数算法

2. 可达性分析算法

Java和C#中都是采用根搜索算法来判定对象是否存活的。这种算法的基本思路是通过一系列名为“GC Roots”的对象作为起始点,从这些节点开始向下搜索,搜索所走过的路径称为引用链,当一个对象到GC Roots没有任何引用链相连时,就证明此对象是不可用的。

可达性分析算法

在Java语言里,可作为GC Roots的兑现包括下面几种:

生存还是死亡?

实际上,在可达性分析算法中,要真正宣告一个对象死亡,至少要经历两次标记过程
如果对象在进行可达性分析后发现没有与GC Roots相连接的引用链,那它会被第一次标记并且进行一次筛选,筛选的条件是此对象是否有必要执行finalize()方法。当对象没有覆盖finalize()方法,或finalize()方法已经被虚拟机调用过,虚拟机将这两种情况都视为没有必要执行。

如果该对象被判定为有必要执行finalize()方法,那么这个对象将会被放置在一个名为F-Queue队列中,并在稍后由一条由虚拟机自动建立的、低优先级的Finalizer线程去执行finalize()方法。finalize()方法是对象逃脱死亡命运的最后一次机会(因为一个对象的finalize()方法最多只会被系统自动调用一次),稍后GC将对F-Queue中的对象进行第二次小规模的标记,如果要在finalize()方法中成功拯救自己,只要在finalize()方法中让该对象重引用链上的任何一个对象建立关联即可。而如果对象这时还没有关联到任何链上的引用,那它就会被回收掉。

回收方法区

在《Java虚拟机规范》中确实说过可以不要求虚拟机在方法区实现垃圾回收,主要是因为在方法区进行垃圾回收的“性价比”很低:在堆中,尤其是在新生代中,常规应用进行一次垃圾回收一般可以回收70%-95%的空间,而永久代的垃圾回收效率远低于此。

永久代的垃圾收集主要回收两部分内容:

所以,在大量使用反射、动态代理的应用中,都必须要求JVM具有类卸载的功能,以保证永久代不会溢出。


上一篇 下一篇

猜你喜欢

热点阅读