一. 引用类型
java引用类型共有以下四种:
1.强引用
所谓强引用("Strong" Reference),就是我们最常见的普通对象引用,只要还有强引用指向一个对象,就能表明对象还“活着”,垃圾收集器不会碰这种对象。对于一个普通的对象,如果没有其他的引用关系,只要超过了引用的作用域或者显式地将相应(强)引用赋值为 null,就是可以被垃圾收集的了,当然具体回收时机还是要看垃圾收集策略。
2.软引用
软引用(SoftReference),是一种相对强引用弱化一些的引用,可以让对象豁免一些垃圾收集,只有当 JVM 认为内存不足时,才会去试图回收软引用指向的对象。JVM 会确保在抛出 OutOfMemoryError 之前,清理软引用指向的对象。软引用通常用来实现内存敏感的缓存,如果还有空闲内存,就可以暂时保留缓存,当内存不足时清理掉,这样就保证了使用缓存的同时,不会耗尽内存。
3.弱引用
弱引用(WeakReference)并不能使对象豁免垃圾收集,仅仅是提供一种访问在弱引用状态下对象的途径。这就可以用来构建一种没有特定约束的关系,比如,维护一种非强制性的映射关系,如果试图获取时对象还在,就使用它,否则重现实例化。它同样是很多缓存实现的选择。
4.幻象引用
对于幻象引用,有时候也翻译成虚引用,你不能通过它访问对象。幻象引用仅仅是提供了一种确保对象被 finalize 以后,做某些事情的机制,比如,通常用来做所谓的 Post-Mortem 清理机制,我在专栏上一讲中介绍的 Java 平台自身 Cleaner 机制等,也有人利用幻象引用监控对象的创建和销毁。
java之所以会有不同的引用类型,是由于对象的引用状态会有垃圾回收产生影响,如对于一些缓存对象,可以使用软引用来构建,当内存充足时,垃圾回收状态与强引用类型一致;当内存不足时,会回收这些对象的内存。
二.使用
1.弱引用的使用
平时,我们使用Object obj = new Object()
创建对象时,创建的就是一个强引用。对于软引用与弱引用,jdk提供了相关的类,列出如下:
SoftReferenceSoftReference(T) SoftReference(T, ReferenceQueue ) T get() ···WeakReference WeakReference(T) WeakReference(T, ReferenceQueue ) T get() ···
可以看到,两个类中,主要使用的是构造方法与get方法,使用示例如下:
//创建一个弱引用,引用的对象是new Object()WeakReference
2.引用队列的使用
谈到各种引用的编程,就必然要提到引用队列。我们在创建各种引用并关联到响应对象时,可以选择是否需要关联引用队列,JVM 会在特定时机将引用 enqueue 到队列里,我们可以从队列里获取引用(remove 方法在这里实际是有获取的意思)进行相关后续逻辑。尤其是幻象引用,get 方法只返回 null,如果再不指定引用队列,基本就没有意义了。看看下面的示例代码。利用引用队列,我们可以在对象处于相应状态时(对于幻象引用,被 finalize 了,处于幻象可达状态),执行后期处理逻辑。
Object counter = new Object();ReferenceQueue refQueue = new ReferenceQueue<>();PhantomReference
三.对象可达性判断
jvm在进行垃圾回收时,决定对象是否可以被清除,会判断该对象是否可达,若对象不可达,则清除。
java通过可达性分析来判断对象是否存活。基本思想是通过一系列称为“GC roots”的对象作为起始点,可以作为根节点的是:
- 虚拟机栈(栈帧中的本地变量表)中引用的对象
- 本地方法栈中JNI(即一般说的Native方法)引用的对象
- 方法区中类静态属性引用的对象
- 方法区中常量引用的对象