jdk从1.2开始,把对象的引用分为四个类型,这四种引用类型从生命周期从长到短依次是:强引用、软引用、弱引用、虚引用。
Java引入这四种引用类型的目标主要有两个:
一个是可以让程序员通过代码的方式控制对象的生命周期;
一个是有利于jvm进行垃圾回收。
强引用
程序中最普遍的默认对象引用,也是程序开发中最常用的引用类型。JVM的垃圾回收期在任何时候都不会回收强引用。即使当内存空间不足抛出内存溢出(OOM),也不会回收具有强引用的对象来释放内存。我们可以显式的赋值对象为null,来告诉gc该对象不存在引用,这时gc就可以回收这个对象,但具体什么时候收集还是要取决于gc的算法。
比如ArraryList类的clear方法中就是通过将引用赋值为null来实现清理工作
/**
* Removes all of the elements from this list. The list will
* be empty after this call returns.
*/
public void clear() {
modCount++;
// clear to let GC do its work
for (int i = 0; i < size; i++)
elementData[i] = null;
size = 0;
}
软引用
软引用用来描述一些有用但不是必需的对象,在Java中用java.lang.ref.SoftReference类来表示。对于软引用关联着的对象,只有在内存不足的时候JVM才会回收该对象。因此,这一点可以很好地用来解决OOM的问题,并且这个特性很适合用来实现缓存:比如网页缓存、图片缓存等。
比如下面的代码,即使obj赋值为null,软引用关联对象在内存充足的情况不会被回收。
public class TestSoftReference {
public static void main(String[] args) {
Obj obj = new Obj("SoftReference");
SoftReference<Obj> sr = new SoftReference<>(obj);
obj = null;
System.gc();
System.out.println(sr.get().getName());
}
}
@Data
@AllArgsConstructor
class Obj {
private String name;
}
运行结果:
SoftReference
弱引用
弱引用用来描述一些非必须的对象。弱引用相比于软引用拥有更短的生命周期,当JVM运行垃圾回收的时候,不论内存是否充足,都会回收只被弱引用对象关联的对象。在java中,用java.lang.ref.WeakReference类来表示。
比如下面的代码,obj赋值为null后,弱引用关联的对象会在执行垃圾回收后被回收。
public class TestWeakReference {
public static void main(String[] args) {
Obj obj = new Obj("WeakReference");
WeakReference<Obj> wr = new WeakReference<>(obj);
System.out.println(wr.get().getName());
System.out.println("----------------");
obj = null;
System.out.println(wr.get().getName());
System.out.println("----------------");
// 推荐gc来回收
System.gc();
System.out.println(wr.get().getName());
}
}
运行结果:
WeakReference
----------------
WeakReference
----------------
Exception in thread "main" java.lang.NullPointerException
at com.xiao.temporary.TestRefrence.main(TestRefrence.java:25)
虚引用
顾名思义,就是形同虚设,即对对象而言是无感知的。与其他几种引用类型不同,虚引用不会影响和决定对象的生命周期。在java中用java.lang.ref.PhantomReference类表示。如果一个对象仅持有虚引用,那么它就和没有任何引用一样,在任何时候都可能被垃圾回收。
虚引用主要用来跟踪对象被垃圾回收的活动(即对象是否存活的监控)。虚引用与软引用和弱引用的一个区别在于:虚引用必须和引用队列(ReferenceQueue)联合使用。当垃圾回收器准备回收一个对象时,如果发现它还有虚引用,就会在回收对象的内存之前,把这个虚引用加入到与之关联的引用队列中。程序可以通过判断引用队列中是否已经加入了虚引用,来了解被引用的对象是否将要被垃圾回收。程序如果发现某个虚引用已经被加入到引用队列,那么就可以在所引用的对象的内存被回收之前采取必要的行动。
比如下面的代码,通过是否入列ReferenceQueue可以判断对象是否被回收。
public class TestPhantomReference {
public static void main(String[] args) {
Obj obj = new Obj("PhantomReference");
ReferenceQueue<Obj> referenceQueue = new ReferenceQueue<>();
PhantomReference<Obj> pr = new PhantomReference<>(obj, referenceQueue);
// 永远为null
System.out.println("pr.get:" + pr.get());
// 是否入队,和是否被回收有关
System.out.println("pr.isEnqueued:" + pr.isEnqueued());
// poll一下referenceQueue中的对象看看
System.out.println("referenceQueue.poll:" + referenceQueue.poll());
System.out.println("----------------");
obj = null;
System.out.println("pr.get:" + pr.get());
System.out.println("pr.isEnqueued:" + pr.isEnqueued());
System.out.println("referenceQueue.poll:" + referenceQueue.poll());
System.out.println("----------------");
// 推荐gc来回收
System.gc();
System.out.println("pr.get:" + pr.get());
System.out.println("pr.isEnqueued:" + pr.isEnqueued());
System.out.println("referenceQueue.poll:" + referenceQueue.poll());
}
}
运行结果:
pr.get:null
pr.isEnqueued:false
referenceQueue.poll:null
----------------
pr.get:null
pr.isEnqueued:false
referenceQueue.poll:null
----------------
pr.get:null
pr.isEnqueued:true
referenceQueue.poll:java.lang.ref.PhantomReference@610455d6
总结
引用类型 | 被垃圾回收时间 | 用途 | 生存时间 |
---|---|---|---|
强引用 | 从来不会 | 对象的一般状态 | JVM停止运行时 |
软引用 | 内存不足时 | 对象缓存 | 内存不足时 |
弱引用 | jvm垃圾回收时 | 对象缓存 | gc运行后 |
虚引用 | 未知 | 未知 | 未知 |
博主真是太厉害了!!!
看的我热血沸腾啊
看的我热血沸腾啊https://www.ea55.com/
哈哈哈,写的太好了https://www.cscnn.com/
《公主的七岁派对》电影片高清在线免费观看:https://www.jgz518.com/xingkong/157670.html
你的文章让我感受到了不一样的风景,谢谢分享。 http://www.55baobei.com/pQYrKbVDeM.html
《有兽焉第四季》国产动漫高清在线免费观看:https://www.jgz518.com/xingkong/135226.html
看到你的文章,我仿佛感受到了生活中的美好。 https://www.4006400989.com/qyvideo/91841.html