在 Java 中,除了基本数据类型的变量,Java基本数据类型有:字符类型char,布尔类型boolean以及数值类型byte、short、int、long、float、double;其它的都是引用类型,指向各种不同的对象。理解这几种引用类型,有助于理解Java对象的生命周期和Java的垃圾回收机制。
引用基本介绍
Java从1.2版本引入了4种引用,这4种引用的级别由高到低依次为:
强引用 > 软引用 > 弱引用 > 虚引用
强引用(StrongReference)
强引用是使用最普遍的对象引用。如果一个对象具有强引用,就表明对象“活着”,垃圾回收器不会回收它。当内存空间不足,Java虚拟机宁愿抛出OutOfMemoryError错误,使程序异常终止,也不会回收具有强引用的对象来解决内存不足的问题。
对于一个普通的对象,如果没有其他的引用,只有超过了强引用的作用域或将显示地强引用赋值为 null,对象才可以被垃圾回收。软引用(SoftReference)
如果一个对象只具有软引用,则内存空间足够,垃圾回收器就不会回收它;如果内存空间不足了,就会回收这些对象的内存。只要垃圾回收器没有回收它,该对象就可以被程序使用。软引用可用来实现内存敏感的缓存,如果还有空闲内存,就可以暂时保留缓存,当内存不足时清理掉,这样就保证了使用缓存的同时,不会耗尽内存。
软引用可以和一个引用队列(ReferenceQueue)联合使用,如果软引用所引用的对象被垃圾回收器回收,Java虚拟机就会把这个软引用加入到与之关联的引用队列中。
弱引用(WeakReference)
弱引用与软引用的区别在于:弱引用的对象拥有更短暂的生命周期。在垃圾回收器线程扫描它所管辖的内存区域的过程中,一旦发现了只具有弱引用的对象,不管当前内存空间足够与否,都会回收它的内存。不过,由于垃圾回收器是一个优先级很低的线程,因此不一定会很快发现那些只具有弱引用的对象。
弱引用可以和一个引用队列(ReferenceQueue)联合使用,如果弱引用所引用的对象被垃圾回收,Java虚拟机就会把这个弱引用加入到与之关联的引用队列中。
虚引用(PhantomReference)
虚引用有时也被翻译为幻象引用、幽灵引用。“虚引用”顾名思义,就是形同虚设,与前面三种引用都不同,虚引用并不会决定对象的生命周期。如果一个对象仅持有虚引用,那么它就和没有任何引用一样,在任何时候都可能被垃圾回收器回收。
虚引用主要用来跟踪对象被垃圾回收器回收的活动。虚引用与软引用和弱引用的一个区别在于:虚引用必须和引用队列(ReferenceQueue)联合使用。当垃圾回收器准备回收一个对象时,如果发现它还有虚引用,就会在回收对象的内存之前,把这个虚引用加入到与之关联的引用队列中。
实例测试引用
- 强引用(StrongReference)
@Test
public void strongReferenceTest() {
Object referent = new Object();
// create strongReference
Object strongReference = referent;
assertSame(referent, strongReference);
referent = null;
System.gc();
// StrongReference 在GC后不会被回收
assertNotNull(strongReference);
}
- 软引用(SoftReference)
@Test
public void softReferenceTest() {
Object referent = new Object();
// create softReference
SoftReference<Object> softReference = new SoftReference<Object>(referent);
assertNotNull(softReference.get());
referent = null;
System.gc();
// soft references 只有在 jvm OutOfMemory 之前才会被回收, 所以它非常适合缓存应用
assertNotNull(softReference.get());
}
- 弱引用(WeakReference)
@Test
public void weakReferenceTest() {
Object referent = new Object();
// create weakReference
WeakReference<Object> weakReference = new WeakReference<Object>(referent);
assertSame(referent, weakReference.get());
referent = null;
System.gc();
// 一旦没有指向 referent 的强引用, weak reference 在 GC 后会被自动回收
assertNull(weakReference.get());
}
- 虚引用(PhantomReference)
@Test
public void phantomReferenceAlwaysNull() {
Object referent = new Object();
// phantom reference必须与ReferenceQueue联合使用
PhantomReference<Object> phantomReference = new PhantomReference<Object>(referent, new ReferenceQueue<Object>());
// phantom reference 的 get 方法永远返回null
assertNull(phantomReference.get());
}
对比
References Type | Purpose | Use | When GCed | Implementing Class |
---|---|---|---|---|
Strong Reference | An ordinary reference. Keeps objects alive as long as they are referenced. | normal reference. | Any object not pointed to can be reclaimed. | default |
Soft Reference | Keeps objects alive provided there’s enough memory. | to keep objects alive even after clients have removed their references (memory-sensitive caches), in case clients start asking for them again by key. | After a first gc pass, the JVM decides it still needs to reclaim more space. | java.lang.ref.SoftReference |
Weak Reference | Keeps objects alive only while they’re in use (reachable) by clients. | Containers that automatically delete objects no longer in use. | After gc determines the object is only weakly reachable. | java.lang.ref.WeakReference java.util.WeakHashMap |
Phantom Reference | Lets you clean up after finalization but before the space is reclaimed (replaces or augments the use of finalize()) | Special clean up processing | After finalization. | java.lang.ref.PhantomReference |