JVM进阶之GC(二)对象存活判断算法
上一篇简单的说明了对象在JVM中的内存分代策略,此文继续来为GC打基础,说说什么样的对象需要被GC,即对象是否存活判定算法。
判定对象存活算法
如何判断对象沦为了垃圾也是门技术。
引用计数法
引用计数法就是给对象加个引用计数器,每有一个地方引用到它时,这个引用计数器就加1。当引用失效的时候,计数器的值就减1,也就是说根据引用计数器的值来判断对象是否存活,若值是0,那么该对象就不再被使用了。
真是如此吗?答案是否定的。试想一下如下图的场景:
AB对象相互引用,那么AB对象的引用计数器的值永远都不会为0,AB就永远都不会被回收,直接造成内存泄漏问题。所以该算法最大的缺点是很难解决对象之间相互引用的问题
。但事实上,如上图情况的相互引用对象会被回收,说明实际不是用引用计数法判定对象存活与否。
可达性分析法
可达性分析法的基本思路是通过一系列的GC Roots对象作为起始点,从这些点向下搜索它们引用的对象,这样可以生成一颗引用树,树的节点就是可达的对象。反之,不在树上的对象即可判定对象已死。来看如下图:
D和E对象相互引用,但是它们没有RC Roots根节点的引用指向,所以D和E在下次垃圾回收时会被处死,而ABC对象在GC Roots的引用树上,会视为存活对象。
那么哪些对象可以作为引用树的根节点呢?
可作为GC Roots的对象
不难想象,作为GC Roots的对象必须是极难被回收的对象,包括了如下几种对象:
- 虚拟机栈(
栈帧中的本地变量表
)中引用的对象,如在方法中定义和使用的变量 - 方法区中的
类静态属性引用的对象
,如static修饰的成员变量 - 方法区中
常量引用的对象
,如static和final共同修饰的常量 - 本地方法栈中
JNI引用的对象
,JNI也就是调的native方法
引用类型与垃圾回收时机
不论是通过以上哪种方式判断对象是否存活,都与引用
相关。java自1.2之后,对引用划分了4种,如下:
强引用
:只要某个对象有强引用与之关联,JVM必定不会回收这个对象,即使在内存不足的情况下,JVM宁愿抛出OutOfMemory错误也不会回收
这种对象。软引用
:软引用是用来描述一些有用但并不是必需的对象,比如引用图片地址等,在Java中用java.lang.ref.SoftReference类来表示。对于软引用关联着的对象,只有在内存不足的时候JVM才会回收
该对象。弱引用
:弱引用也是用来描述非必需对象的,当JVM进行垃圾回收时,无论内存是否充足,都会回收被弱引用关联的对象。也就是说被弱引用关联的对象,只能生存到下一次垃圾收集发生之前
。虚引用(幽灵引用或幻影引用)
:虚引用和前面的软引用、弱引用不同,它并不影响对象的生命周期。在java中用java.lang.ref.PhantomReference类表示。如果一个对象与虚引用关联,则跟没有引用与之关联一样,在任何时候都可能被垃圾回收器回收。为一个对象设置虚引用关联的唯一目的就是能在这个对象被收集器回收时收到一个系统通知
。与弱引用区别:在GC时会被通知。
好了,今天点到为止,下篇谈谈垃圾回收算法和垃圾回收器。