目录
Java中提供这四种引用类型主要有两个目的:
- 可以让程序员通过代码的方式决定某些对象的生命周期;
- 有利于JVM进行垃圾回收
一、强引用
定义
是指在程序代码之中普遍存在的引用赋值,即类似“Object obj=new Object()”这种引用关系。无论任何情况下,只要强引用关系还存在,垃圾收集器就永远不会回 收掉被引用的对象。
特点
强引用有引用变量指向时永远不会被垃圾回收,JVM宁愿抛出OutOfMemory错误也不会回收这种对象。
使用场景
我们平常大部分使用的场景都是使用了强引用,比如new创建对象,反射获得一个对象等
代码
public static void main(String[] args) {
Object object = new Object();
Object strongRef = object;
object = null;
System.gc();
try {
Thread.sleep(1000);
} catch (Exception e) {
// TODO: handle exception
}
System.out.println("Strong: " + strongRef.toString());
}
输出
Strong: java.lang.Object@7ea987ac
如果想中断强引用和某个对象之间的关联,可以显示地将引用赋值为null,这样一来的话,JVM在合适的时间就会回收该对象。比如Vector类的clear方法中就是通过将引用赋值为null来实现清理工作的。
强引用也是导致内存泄露的主要原因
二、软引用
定义
只被软引用关联着的对象,在系统将要发生内 存溢出异常前,会把这些对象列进回收范围之中进行第二次回收,如果这次回收还没有足够的内存, 才会抛出内存溢出异常。
特点
如果一个对象只具有软引用,那就类似于可有可物的生活用品。如果内存空间足够,垃圾回收器就不会回收它,如果内存空间不足了,就会回收这些对象的内存。只要垃圾回收器没有回收它,该对象就可以被程序使用。软引用可用来实现内存敏感的高速缓存。
软引用可以和一个引用队列(ReferenceQueue)联合使用,如果软引用所引用的对象被垃圾回收,Java虚拟机就会把这个软引用加入到与之关联的引用队列中。
使用场景
适用于网页缓存、图片缓存,防止内存溢出,在内存充足的时候,缓存对象会一直存在,在内存不足的时候,缓存对象占用的内存会被垃圾收集器回收。
代码
JVM参数 -Xms10m -Xmx10m -XX:+PrintGCDetails
public static void main(String[] args) {
Object obj = new Object();
SoftReference<Object> softRef = new SoftReference<Object>(obj);
System.out.println(obj);
System.out.println(softRef.get());
// 对象要设置为null,否则不会被回收。原因:通过设置为null让对象失去引用,方便GC
// 备注:因为在这个main方法中(主线程),方法未结束之前,不设置为null,对象是不会失去引用的。
obj = null;
// 当内存不足时,会自动触发GC操作,这里就无需手动GC
try {
byte[] b = new byte[30 * 1024 * 1024];
} catch (Exception e) {
// TODO: handle exception
} finally {
System.out.println(obj);
System.out.println(softRef.get());
}
}
输出
null
null
软引用在内存不够时,通过系统的GC,回收对象了
三、弱引用
定义
被弱引用关联的对象只 能生存到下一次垃圾收集发生为止。
特点
如果一个对象只具有弱引用,那就类似于可有可物的生活用品。 弱引用与软引用的区别在于:只具有弱引用的对象拥有更短暂的生命周期。在垃圾回收器线程扫描它 所管辖的内存区域的过程中,一旦发现了只具有弱引用的对象,不管当前内存空间足够与否,都会回收它的内存。不过,由于垃圾回收器是一个优先级很低的线程, 因此不一定会很快发现那些只具有弱引用的对象。
使用场景
弱引用用于生命周期更短的,对内存更敏感的场景中,比如占用内存很大的Map,java api中就提供了WeakHashMap使用,就会使得大Map被及时清理掉。
代码
public static void main(String[] args) {
Object obj = new Object();
WeakReference<Object> weakRef = new WeakReference<Object>(obj);
System.out.println(obj); // java.lang.Object@7852e922
System.out.println(weakRef.get()); // java.lang.Object@7852e922
// 对象要设置为null,否则不会被回收。原因:通过设置为null让对象失去引用,方便GC
// 备注:因为在这个main方法中(主线程),方法未结束之前,不设置为null,对象是不会失去引用的。
obj = null;
// 这里通过手动触发GC操作。否则内存充足的情况下很难自动触发GC
System.gc();
System.out.println(obj); // null
System.out.println(weakRef.get()); // null
}
输出
java.lang.Object@7ea987ac
java.lang.Object@7ea987ac
null
null
在内存充足的情况下,弱引用的对象也被回收了。
四、虚引用
定义
是最弱的一种引用关系。一个对象是否有虚引用的 存在,完全不会对其生存时间构成影响,也无法通过虚引用来取得一个对象实例。为一个对象设置虚 引用关联的唯一目的只是为了能在这个对象被收集器回收时收到一个系统通知。
特点
又称为幽灵引用或幻影引用,,虚引用既不会影响对象的生命周期,也无法通过虚引用来获取对象实例,仅用于在发生GC时接收一个系统通知。
使用场景
判断一个对象是否被垃圾回收了,跟踪对象被垃圾回收回收的活动。一般可以通过虚引用达到回收一些非java内的一些资源比如堆外内存的行为。
代码
public static void main(String[] args) {
Object obj = new Object();
ReferenceQueue<Object> queue = new ReferenceQueue<Object>();
PhantomReference<Object> pr = new PhantomReference<Object>(obj, queue);
System.out.println(pr.get()); // null
}
输出
null
虚引用的主要作用是跟踪对象被垃圾回收的状态。仅仅是提供了一种确保对象被finalize以后,做某些事情的机制。PhantomRefrence的get方法总是返回null,因此无法访问对应的引用对象。其意义在于说明一个对象已经进入finalization阶段,可以被GC回收,用来实现比finalization机制更灵活的回收操作。