引用类型
在 JDK 1.2 之后,Java 对引用的概念进行了扩充,将引用分为了:强引用(Strong Reference)、软引用(Soft Reference)、弱引用(Weak Reference)、虚引用(Phantom Reference)4 种,这 4 种引用的强度依次减弱。
1. 强引用(StrongReference)
当一个实例对象被强引用时,垃圾回收器就不会回收该对象,内存不足时抛出 OutOfMemeryError 异常也不会回收强引用对象。
测试案例:
// 定义当前内存 -Xms2M -Xmx3M
// 当内存使用为 1M 时,程序运行正常
byte[] buff1 = new byte[1024 * 1024];
// 当内存使用为 2M 时,程序运行正常
byte[] buff2 = new byte[1024 * 1024];
// 当内存使用为 3M 时,内存溢出
byte[] buff3 = new byte[1024 * 1024];
2. 软引用(SoftReference)
当实例对象只具有软引用时,内存不足的时候垃圾回收器会将软引用对象回收。
测试案例:
List<SoftReference<byte[]>> list = new ArrayList<>();
for (int i = 0; i < 5; i++) {
SoftReference<byte[]> sr = new SoftReference<>(new byte[1024 * 1024]);
list.add(sr);
}
for (SoftReference<byte[]> reference : list) {
System.out.println("获取的引用数据:" + reference.get());
}
3. 弱引用(WeakReference)
只要触发了垃圾回收,无论内存空间是否充足,都会将弱引用对象回收。
测试案例:
WeakReference<byte[]> wr = new WeakReference<>(new byte[1024 * 512]);
System.out.println("清除前数据:" + wr.get());
// 通知GC清除垃圾
System.gc();
System.out.println("清除后数据:" + wr.get());
执行 System.gc() 方法只通知JVM回收垃圾,但是并不是立刻执行垃圾回收
使用场景:WeakHashMap(键失去强引用后,触发GC时键和值将会回收移除),ThreadLocalMap防止内存泄漏
4. 虚引用(PhantomReference)
只要实例对象被回收,虚引用对象就会被放入引用队列中,虚引用对象必须配合引用队列使用。
虚引用之所以需要配合引用队列是因为,虚引用本身无法获取到引用的对象,只能感知对象被回收,当对象被回收后,虚引用本身就没意义了。当有引用队列以后,虚引用对象被加入到队列后,就可以知道虚引用对象失去了虚引用,就可以得知对象被回收,然后进行对象回收后的操作。
测试案例:
ReferenceQueue<byte[]> queue = new ReferenceQueue<>();
PhantomReference<byte[]> pr = new PhantomReference<>(new byte[1024 * 512], queue);
System.out.println("获取的引用数据:" + pr.get());
System.gc();
System.out.println("队列中的虚引用:" + queue.poll());
5. 引用队列(ReferenceQueue)
软引用本身也是一个 Java 对象,当软引用对象被回收以后本身已经没有作用了,调用 get() 方法返回 null ,所以需要一个合适的清除机制,避免大量软引用对象的创建导致内存泄漏。在 Java 中提供了 ReferenceQueue 引用队列,**与软引用、弱引用以及虚引用一起配合使用,用作保存被清除引用的 Reference 对象**,当 Reference 对象中引用被清除后加入队列。<br /> 在 SoftReference 对象构造方法中添加引用队列,调用 ReferenceQueue 对象的 poll() 方法时,会返回被清除软引用的 SoftReference 对象,并从队列中移除。<br />测试案例:
List<SoftReference<byte[]>> list = new ArrayList<>();
ReferenceQueue<byte[]> queue = new ReferenceQueue<>();
for (int i = 0; i < 5; i++) {
SoftReference<byte[]> sr = new SoftReference<>(new byte[1024 * 512], queue);
System.out.println("所创建的软引用:" + sr);
list.add(sr);
}
Reference<? extends byte[]> reference;
while ((reference = queue.poll()) != null) {
System.out.println("被清除的软引用:" + reference);
}