个性化阅读
专注于IT技术分析

你真的知道Java中的4种引用类型吗?

本文概述

Java提供了四个级别的引用:SoftReference, FinalReference, WeakReference和PhantomReference。在这四种引用类型中, 只有FinalReference类在包中可见, 而其他三种引用类型都是公共的, 可以直接在应用程序中使用。参考类型的类结构如图所示。

你真的知道Java中的4种引用类型吗

1. FinalReference

Java中的引用类似于C中的指针。并且你可以通过引用对堆中的对象进行操作。这是一个例子:

StringBuffer stringBuffer = new StringBuffer("Helloword");

变量str指向StringBuffer实例所在的堆空间, 你可以使用str操纵对象。

你真的知道Java中的4种引用类型吗

这是FinalReferences的功能:

  1. FinalReferences提供对目标对象的直接访问。
  2. FinalReferences指向的对象不会在任何时候被系统回收。 JVM会抛出OOM异常, 而不是回收FinalReference指向的对象。
  3. FinalReferences可能会导致内存泄漏。

2.软引用

除FinalReference外, SoftReference是最强的引用类型。可以通过java.lang.ref.SoftReference使用SoftReferences。 JVM不会快速回收持有SoftReference的对象。 JVM将根据当前堆的使用情况确定何时回收。仅当堆使用率接近阈值时, 才会收集SoftReferenced对象。因此, SoftReference可用于实现对内存敏感的缓存。

SoftReference的特征是可以保留对Java对象的软引用的实例。软引用的存在不会阻止垃圾回收线程回收Java对象。这意味着一旦SoftReference保存了对Java对象的软引用, 在GC线程回收Java对象之前, SoftReference类提供的get()方法将返回对该Java对象的强引用。一旦GC线程回收了Java对象, get()方法将返回null。

以下是如何使用SoftReferences的示例。

在你的IDE中设置参数-Xmx2m -Xms2m, 并将堆内存大小指定为2m。

@Test
public void test3(){
	MyObject obj = new myObject();
	SoftReference sf = new SoftReference<>(obj);
	obj = null;
	System.gc();
//        byte[] bytes = new byte[1024*100];
//        System.gc();
	System.out.println("Is Collected: "+sf.get());
}

结果如下:

Is Collected: cn.zyzpp.MyObject@42110406

打开注释的语句new byte [1024 * 100], 该语句请求一个大的堆空间块, 从而使堆内存变得紧张。再次显式调用GC, 结果如下:

Is Collected: null

请注意, 在系统内存不足的情况下, SoftReferences将被回收。

3.弱引用

WeakReference是一种参考类型, 比SoftReference弱。在GC系统中, 无论何时找到弱引用, 无论系统堆空间是否足够, 对象都将被回收。而且, 你可以使用java.lang.ref.WeakReference实例来保存对Java对象的弱引用。

public void test3(){
	MyObject obj = new MyObject();
	WeakReference sf = new WeakReference(obj);
	obj = null;
	System.out.println("Is Collected: "+sf.get());
	System.gc();
	System.out.println("Is Collected: "+sf.get());
}

结果如下:

Is Collected: cn.zyzpp.MyObject@42110406
Is Collected: null

SoftReference和WeakReference非常适合用于保存可选的缓存数据。如果使用它们, 则在系统内存不足时, 将回收缓存的数据而不会引起内存溢出。当内存资源足够时, 缓存的数据可以存在很长时间, 这将加速系统。

4.PhantomReference

PhantomReference是所有类型中最弱的。持有PhantomReference的对象几乎与没有引用相同, 并且可以随时由垃圾收集器回收。当尝试通过PhantomReferences的get()方法获得强大的引用时, 它将始终失败。并且PhantomReferences必须与参考队列一起使用, 以跟踪垃圾回收过程。

当垃圾回收器要回收对象时, 如果发现有一个PhantomReference, 它将在垃圾回收后销毁该对象, 并将PhantomReference添加到引用队列中。根据判断是否已向引用队列中添加了PhantomReference, 程序可以确定是否需要对引用的对象进行垃圾回收。如果程序发现PhantomReference已添加到引用队列中, 则将在回收引用对象的内存之前采取必要的措施。

public void test3(){
	MyObject obj = new MyObject();
	ReferenceQueue<Object> referenceQueue = new ReferenceQueue<>();
	PhantomReference sf = new PhantomReference<>(obj, referenceQueue);
	obj = null;
	System.out.println("Is Collected: "+sf.get());
	System.gc();
	System.out.println("Is Collected: "+sf.get());
}

结果如下:

Is Collected: null
Is Collected: null

PhantomReference上的get()操作始终返回null, 因为sf.get()方法的实现如下:

public T get() {
	return null;
}

5, WeakHashMap类及其实现

WeakHashMap类位于java.util包中。它实现了Map接口, 并且是HashMap的实现。它使用WeakReferences作为内部数据的存储方案。 WeakHashMap是弱引用的典型应用程序, 可以用作简单的缓存表解决方案。

以下两段代码分别使用WeakHashMap和HashMap保存大量数据:

@Test
public void test4(){
	Map map;
	map = new WeakHashMap<String, Object>();
	for (int i =0;i<10000;i++){
		map.put("key"+i, new byte[i]);
	}
//        map = new HashMap<String, Object>();
//        for (int i =0;i<10000;i++){
//            map.put("key"+i, new byte[i]);
//        }
}

它使用-Xmx2M来限制堆内存。使用WeakHashMap的代码结束运行, 并且使用HashMap的代码段引发异常。

java.lang.OutOfMemoryError: Java heap space

可以看出, 当系统内存不足时, WeakHashMap将使用WeakReferences, 并自动释放保存WeakReferences的内存数据。

但是, 如果WeakHashMap的键都在系统中都保留了FinalReferences, 则WeakHashMap将退化为普通的HashMap, 因为无法自动清除所有项目。

赞(0)
未经允许不得转载:srcmini » 你真的知道Java中的4种引用类型吗?

评论 抢沙发

评论前必须登录!