Java 中都有哪些引用类型?
强引用
在 Java 中最常见的就是强引用,把一个对象赋给一个引用变量,这个引用变量就是一个强引用。当一个对象被强引用变量引用时,它处于可达状态,它是不可能被垃圾回收机制回收的。因此强引用是造成 Java 内存泄漏的主要原因之一。
Object obj = new Object(); //只要obj还指向Object对象,Object对象就不会被回收 obj = null; //手动置null
只要强引用存在,垃圾回收器将永远不会回收被引用的对象,哪怕内存不足时,JVM也会直接抛出OutOfMemoryError,不会去回收。如果想中断强引用与对象之间的联系,可以显示的将强引用赋值为null,这样一来,JVM就可以适时的回收对象了
软引用
软引用是用来描述一些非必需但仍有用的对象。在内存足够的时候,软引用对象不会被回收,只有在内存不足时,系统则会回收软引用对象,如果回收了软引用对象之后仍然没有足够的内存,才会抛出内存溢出异常。这种特性常常被用来实现缓存技术,比如网页缓存,图片缓存等。
在 JDK1.2 之后,用java.lang.ref.SoftReference类来表示软引用。
在运行下面的Java代码之前,需要先配置参数 -Xms2M -Xmx3M,将 JVM 的初始内存设为2M,最大可用内存为 3M。
public class TestOOM {
private static List<Object> list = new ArrayList<>();
public static void main(String[] args) {
testSoftReference();
}
private static void testSoftReference() {
for (int i = 0; i < 10; i++) {
byte[] buff = new byte[1024 * 1024];
SoftReference<byte[]> sr = new SoftReference<>(buff);
list.add(sr);
}
System.gc(); //主动通知垃圾回收
for(int i=0; i < list.size(); i++){
Object obj = ((SoftReference) list.get(i)).get();
System.out.println(obj);
}
}
}
打印结果
我们发现无论循环创建多少个软引用对象,打印结果总是只有最后一个对象被保留,其他的obj全都被置空回收了。
这里就说明了在内存不足的情况下,软引用将会被自动回收。
弱引用
弱引用需要用 WeakReference 类来实现,它比软引用的生存期更短,对于只有弱引用的对象来说,只要垃圾回收机制一运行,不管 JVM 的内存空间是否足够,总会回收该对象占用的内存。
private static void testWeakReference() {
for (int i = 0; i < 10; i++) {
byte[] buff = new byte[1024 * 1024];
WeakReference<byte[]> sr = new WeakReference<>(buff);
list.add(sr);
}
System.gc(); //主动通知垃圾回收
for(int i=0; i < list.size(); i++){
Object obj = ((WeakReference) list.get(i)).get();
System.out.println(obj);
}
}
虚引用
虚引用(Phantom Reference)是Java中四种引用类型之一,也是最弱的一种引用类型。虚引用的作用是帮助对象在被垃圾回收器回收时,可以在回收之前进行必要的清理工作。虚引用并不能通过它访问对象本身,也不能通过它访问对象的任何属性或方法,因为它的get()方法总是返回null。虚引用主要用于管理堆外内存,例如NIO Direct Memory中的内存。当虚引用所引用的对象被垃圾回收器回收时,虚引用会被放入一个ReferenceQueue中,以便在必要时进行清理工作。虚引用一般与ReferenceQueue一起使用,通过检查ReferenceQueue中的引用对象,可以确定对象已经被回收,从而进行相关的清理工作。虚引用通常由java.lang.ref.PhantomReference类来实现。
public class PhantomReference<T> extends Reference<T> {
/**
* Returns this reference object's referent. Because the referent of a
* phantom reference is always inaccessible, this method always returns
* <code>null</code>.
*
* @return <code>null</code>
*/
public T get() {
return null;
}
public PhantomReference(T referent, ReferenceQueue<? super T> q) {
super(referent, q);
}
}
引用队列(ReferenceQueue)
引用队列(ReferenceQueue)是Java中用于管理引用对象的队列。当一个对象被垃圾回收器回收时,如果该对象有一个与之关联的引用队列,那么该引用对象就会被放入该引用队列中。通过引用队列,可以确定对象是否被垃圾回收器回收,从而进行相关的清理工作。
引用队列通常与弱引用、软引用和虚引用一起使用。当弱引用、软引用或虚引用所引用的对象被垃圾回收器回收时,会将该引用对象放入与之关联的引用队列中。通过检查引用队列中的引用对象,可以确定对象已经被回收,从而进行必要的清理工作。
引用队列的使用非常灵活,可以根据不同的需求来选择不同的引用类型和清理工作。例如,对于一些需要进行资源释放的对象,可以使用虚引用和引用队列来进行资源的清理工作。
骚戴理解:注意引用队列并不可以和强引用一起使用,与软引用、弱引用不同,虚引用必须和引用队列一起使用。