java中除了基本数据类型的变量(int、long等),剩下的都是引用类型的变量,一共有四种不同的引用类型。
一、强引用(Strong Reference)
强引用就是最常见的对某个对象的引用,如下代码变量o就是对所创建的Object对象的一个强引用。
Object o = new Object();
存在强引用的对象,不会被垃圾回收,即便发生了OutOfMemoryError,我们来看如下的测试代码:
/**
* 这是一个大对象
* @author 白吃的午餐
*
*/
public class BigObject {
private String name;
private int[] a = new int[1024];
public BigObject(String name) {
this.name = name;
}
@Override
public String toString() {
return "BigObject [name=" + name + "]";
}
}
public class StrongReferenceTest {
public static void main(String[] args) {
List bigs = new LinkedList();
for(int i=0; i<1000; i++) {
BigObject bo = new BigObject("BigObject_" + i);
bigs.add(bo);
}
}
}
输出:
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
at com.lizhihong.reference.BigObject.
at com.lizhihong.reference.StrongReferenceTest.main(StrongReferenceTest.java:12)
二、软引用(Soft Reference)
软引用是强度仅次于强引用的一种引用类型,当JVM认为内存不足时,会回收软引用所指向的对象
public class SoftReferenceTest {
public static void main(String[] args) throws InterruptedException {
List> bigs = new LinkedList>();
ReferenceQueue rq = new ReferenceQueue();
BigObject bo = new BigObject("BigObject");
SoftReference sr = new SoftReference(bo, rq);
bo = null;
System.gc();
//内存充足,对象不会被回收,仍然可以被获取到
System.out.println(sr.get());
//内存不足时,会回收软引用指向的对象,不会抛出OutOfMemoryError
for(int i=0; i<1000; i++) {
BigObject bo2 = new BigObject("BigObject_" + i);
SoftReference sr2 = new SoftReference(bo2);
bigs.add(sr2);
bo = null;
}
//对象已经被回收,返回null
System.out.println(sr.get());
}
}
输出:
BigObject [name=BigObject]
null
三、弱引用(Weak Reference)
弱引用是强度次于强引用和软引用的一种引用类型,JVM每次GC时,都有可能回收弱引用指向的对象
public class WeakReferenceTest {
public static void main(String[] args) {
BigObject bo = new BigObject("BigObject_0");
WeakReference wr = new WeakReference(bo);
bo = null;
System.gc();
//与软引用不同,jvm每次gc时都有可能回收弱引用指向的对象,此处输出为null
System.out.println(wr.get());
}
}
输出
null
四、虚引用(Phantom Reference)
虚引用的概念比较难理解,你不能通过一个虚引用访问它指向的对象,PhantomReference的get方法永远返回null,仅仅是提供了对象被实际回收前做某些事情的机制,有点类似于finalize方法,但这个机制其实发生在finalize之后。
首先我们来澄清一个说法:虚引用是强度小于弱引用的一种引用类型
这个说法我个人觉得不完全正确,我们来看下面的这段代码会输出什么。如果虚引用是强度更弱的一种引用类型,下面这段代码应该不会报错,因为GC会正常回收虚引用指向的对象,就像软引用和弱引用一样,但实际执行的情况呢
public class PhantomReferenceTest1 {
public static void main(String[] args) {
List> bigs = new LinkedList>();
ReferenceQueue rq = new ReferenceQueue();
for(int i=0; i<1000; i++) {
BigObject bo = new BigObject("BigObject_" + i);
PhantomReference pr = new PhantomReference(bo, rq);
bigs.add(pr);
bo=null;
}
}
}
输出:
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
at com.lizhihong.reference.BigObject.
at com.lizhihong.reference.PhantomReferenceTest1.main(PhantomReferenceTest1.java:16)
OutOfMemoryError,说明虚引用指向的对象并没有被回收,这是为什么?
下面来说说我的理解,如有错误的地方,还请大家指教
1、以弱引用类型举例(软引用类似),当我们创建一个弱引用的时候,最终会调用Reference如下的构造函数
private T referent; /* Treated specially by GC */
Reference(T referent, ReferenceQueue super T> queue) {
this.referent = referent;
this.queue = (queue == null) ? ReferenceQueue.NULL : queue;
}
referent,分明就是一个强引用,它所指向的对象为什么会被回收呢
2、当JVM执行GC,回收弱引用所指向的对象时,实际上JVM会先把referent置为null,这样此前referent指向的对象就没有任何引用了,可以被JVM回收,实际情况正式这样的,我们来看下WeakReference的java doc说明
/**
* Weak reference objects, which do not prevent their referents from being
* made finalizable, finalized, and then reclaimed. Weak references are most
* often used to implement canonicalizing mappings.
*
*
Suppose that the garbage collector determines at a certain point in time
* that an object is weakly
* reachable. At that time it will atomically clear all weak references to
* that object and all weak references to any other weakly-reachable objects
* from which that object is reachable through a chain of strong and soft
* references. At the same time it will declare all of the formerly
* weakly-reachable objects to be finalizable. At the same time or at some
* later time it will enqueue those newly-cleared weak references that are
* registered with reference queues.
*
* @author Mark Reinhold
* @since 1.2
*/
3、为什么虚引用指向的对象没有被回收,同样我们查看PhantomReference的java doc说明
/**
* Phantom reference objects, which are enqueued after the collector
* determines that their referents may otherwise be reclaimed. Phantom
* references are most often used for scheduling pre-mortem cleanup actions in
* a more flexible way than is possible with the Java finalization mechanism.
*
*
If the garbage collector determines at a certain point in time that the
* referent of a phantom reference is * href="package-summary.html#reachability">phantom reachable, then at that
* time or at some later time it will enqueue the reference.
*
*
In order to ensure that a reclaimable object remains so, the referent of
* a phantom reference may not be retrieved: The get
method of a
* phantom reference always returns null
.
*
*
Unlike soft and weak references, phantom references are not
* automatically cleared by the garbage collector as they are enqueued. An
* object that is reachable via phantom references will remain so until all
* such references are cleared or themselves become unreachable.
*
* @author Mark Reinhold
* @since 1.2
*/
4、虚引用指向的对象什么时候被回收,这取决于JVM