1、对象引用:
(a)对象状态的判断:
<1> 引用计数算法:无法解决对象相互引用的问题。
<2> 根搜索算法:主流的判断对象是否存活的算法。
(1)基本思路:通过一系列的名为:“GC Roots”的对象作为起始点,从这些节点开始向下搜索,搜索所走过的路径为引用链(Reference Chain),当一个对象到GC Roots没有任何引用链相关联时,证明此对象是不可用的,所以它们将会被判断为是可收回的对象。
(2)Java中,GC Roots的对象包括下面几种:
a:虚拟机栈(栈帧中的本地变量表)中的引用的对象;
b:方法区中的类静态属性引用的对象;
c:方法区中的常量引用的对象;
d:本地方法栈JNI(Native方法)的引用的对象。
(3) GC Roots对象结构图,如下图:
(b) Java1.2之后,Java重新定义了对象的引用:
对象引用类型分为 强引用、软引用、弱引用和虚引用。
强引用: 就是我们一般声明对象是时虚拟机生成的引用,如:Object obj=new Object() 。强引用环境下,垃圾回收时需要严格判断当前对象是否被强引用,如果被强引用,则不会被垃圾回收。
软引用: 软引用一般被做为缓存来使用。与强引用的区别是,软引用在垃圾回收时,虚拟机会根据当前系统的剩余内存来决定是否对软引用进行回收。如果剩余内存比较紧张,则虚拟机会回收软引用所引用的空间;如果剩余内存相对富裕,则不会进行回收。换句话说,虚拟机在发生OutOfMemory时,肯定是没有软引用存在的。存活时间可通过-XX:SoftRefLRUPolicyMSPerMB来进行控制。
弱引用: 弱引用与软引用类似,都是作为缓存来使用。但与软引用不同,弱引用在进行垃圾回收时,是一定会被回收掉的,因此其生命周期只存在于一个垃圾回收周期内。
虚引用:一个对象是否有虚引用的存在,完全不会对其生存时间构成影响,也无法通过虚引用来获取一个对象实例。唯一的目的:希望能在这个对象被搜集器回收时收到一个系统通知。
总结:
强引用不用说,我们系统一般在使用时都是用的强引用。而“软引用”和“弱引用”比较少见。他们一般被作为缓存使用,而且一般是在内存大小比较受限的情况下做为缓存。常见的是被使用在桌面应用系统的缓存。
(c)生存或者死亡?
在根算法不可达的对象,也并非是“非死不可”的。至少需要经历2次标记过程:
<1> 如果对象在进行根算法搜索之后,发现没有与GC Roots相连接的引用链,它将会第一次标记并且进行一次筛选,筛选的条件是此对象是否有必要执行finalize()方法。
<2> 如果该对象有必须执行finalize()方法,将会被放置在一个F-Queue的队列中,稍后由一条虚拟机自动建立的,低优先级的Finalizer线程去执行(执行即为触发该方法)。
<3> finalize()方法是对象逃脱死亡的最后一次机会,稍后GC将对F-Queue中的对象进行第二次小规模的标记,如果对象要在finalize()中成功拯救自己——只要重新与引用链上的任何一个对象建立关联即可。
(d)回收方法区:
很多人认为方法区(或HotSpot虚拟机中的持久代)是没有垃圾回收的。
实际上是有的,只是垃圾收集的效率很低。
永久代的垃圾收集主要回收2部分内容:废弃常量和无用的类。
<1> 回收废弃常量与回收Java堆中的对象非常类似:当常量无任何引用,如果此时发生内存回收,这个常量被系统请出常量池。常量池中的其他类(接口)、方法、字段的符号引用也与此类似。
<2> 回收无用的类的条件比较苛刻。类必须要同时满足以下3个条件才能算是“无用的类”:
(1) 该类的所有实例都已被回收,即java堆中不存在该类的任何实例。
(2) 加载该类的ClassLoader已经被回收。
(3) 该类对应的java.lang.Class对象没有在任何地方被引用,无法在任何地方通过反射访问该类的方法。
满足上述条件之后,类可能被回收。那是否被回收,HotSpot提供下列参数进行控制:
(1)是否被回收:-Xnoclassgc参数来进行控制。
(2)查看类的加载信息:-verbose:class及-XX:+TraceClassLoading(可以再product版的虚拟机中使用)。
(3)查看类的卸载信息:-verbose:class及-XX:+TraceClassUnLoading(需要fastdebug版的虚拟机支持)。