java中的强引用,软引用,弱引用,虚引用
什么是强引用,软引用,弱引用,虚引用?
在JDK1.2 之前,如果一个对象不被任何变量引用,则程序无法再次使用这个对象,这个对象最终会被GC(GabageCollection 垃圾回收)。如果后面还要用这个对象,就只能新建一个。
在JDK1.2之后,就提供了四种引用。主要有两个目的:1可以在代码中决某些对象的生命周期。2优化回收机制。
强引用 StrongReference
我们一般创建对象的过程都是强引用,比如我们new一个对象。
Object o = new Object(); String str = "123";
如果某个对象是强引用,JVM 不会回收这个对象,即使内存不足,JVM宁愿抛出OutOfMemory错误也不会回收这个对象。基于这种情况,我们在使用完对象后如果想让JVM回收对象就需要将对象弱化,就是将它赋值为null。 局部方法内的强引用会随着方法的结束退栈而自动清除引用。
Object o = new Object(); o = null;
java集合类的强引用方法无法采用制空方式,只有采用clear() 将内存数组中存放的引用类型进行内存释放。
ArrayList<Object> list = new ArrayList<>(); list.add(123); list.add(123); list.add(123); list.add(123); list.clear(); clear的源码就是遍历数组然后将数组元素制空。 public void clear() { modCount++; // clear to let GC do its work for (int i = 0; i < size; i++) elementData[i] = null; size = 0; }
软引用 SoftReference
软引用是用来描述一些有用但并不是必须的对象,适合用来实现缓存,如浏览器的后退按钮,JVM内存空间充足就存储在内存中,如果空间不足就将其回收掉
//强引用 Object o = new Object(); //注意 此时的o对象就包含了强引用o 和软引用 softReference SoftReference<Object> softReference = new SoftReference<>(o);
软引用可以和一个引用队列(ReferenceQueue)联合使用,如果软引用所引用对象被GC,JVM虚拟机就会把这个软引用加入到与之关联的引用队列中。
ReferenceQueue<Object> refer = new ReferenceQueue<>(); String string = new String("123"); SoftReference<String> reference = new SoftReference<>(string, refer); //制空,取消强引用 string=null; System.gc();//尝试释放被丢弃对象占用的内存 System.out.println(reference.get());//123 Reference<?> reference1 = refer.poll(); System.out.println(reference1);//null
我们调用System.gc()方法指示起到通知作用,JVM什么时候回收对象是JVM自己的状态决定 的,即使扫描到软引用对象也不一定会回收,只有内存不够的时候才会回收。
弱引用 WeakReference
弱引用是用来描述非必须对象的,无论内存是否充足,Jvm都有可能回收弱引用关联的对象。
弱引用和软引用的区别:
弱引用有更短的生命周期,她只能生存到下一次垃圾回收之前。
因为垃圾回收器是一个优先级很低的线程,因此不一定会很快发现那些只具有弱引用的对象
String s = new String("123"); WeakReference<String> stringWeakReference = new WeakReference<>(s); s = null;
如果一个对象偶尔使用,并希望在使用的时候随时就能获取,但又不想影响此对象的垃圾收集,我们就应该使用WeakReference来标记此对象
弱引用也可以和一个引用队列联合使用,如果弱引用所引用的对象被垃圾回收,JVM虚拟机就会把这个弱引用加入到与之关联的引用队列中。
String s = new String("123"); ReferenceQueue<Object> referenceQueue = new ReferenceQueue<>(); WeakReference<String> stringWeakReference = new WeakReference<>(s,referenceQueue); s = null; System.gc();
虚引用PhantomReference
虚引用并不会决定对象的生命周期,一个对象仅持有虚引用,那么它就和没有任何引用一样,在任何时候都有可能被垃圾回收。
虚引用主要用来跟踪对象被垃圾回收的活动。虚引用与软引用和弱引用的一个区别在于:虚引用必须和引用队列(ReferenceQueue)联合使用。当垃 圾回收器准备回收一个对象时,如果发现它还有虚引用,就会在回收对象的内存之前,把这个虚引用加入到与之关联的引用队列中。
String s1 = new String("123"); ReferenceQueue<Object> objectReferenceQueue = new ReferenceQueue<>(); PhantomReference<String> stringPhantomReference = new PhantomReference<>(s1, objectReferenceQueue);
程序可以通过引用队列是否已经加入了虚引用,来了解被引用对象是否将要进行垃圾回收,如果程序发现某个虚引用已经被加入到引用队列,那么就可以在所引用的对象的内存被回收之前采取必要的行动。
四种引用的区别
级别 | 何时被回收 | 生成时间 |
---|---|---|
强引用 | 从不 | JVM停止时 |
软引用 | 内存空间不足 | 内存不足时终止 |
弱引用 | 对象未被引用时 | GC后 |
虚引用 | 对象被回收时 | 内存使用控制引用队列对象被回收 |
使用场景
强引用(StrongReference)
日常代码中使用最多的,不再使用的时候,我们进行置空才可能被回收,集合需要调用clear方法。
软引用( SoftReference )
非常适合用来创建缓存,当系统内存不足时,缓存中的内存就可以被释放。
图片缓存:内存缓存中的缓存事以这种引用保存点的,使得JVM在发生OOM之前,可以回收这部分缓存
网页缓存。
//获取页面进行浏览 Object o = new Object(); //浏览后设置为软引用 SoftReference reference = new SoftReference(s); if (reference.get()!=null){ //还没被回收期回收,直接获取。 o = reference.get(); }else { //由于内存有限,所以对软引用的对象回收了。 Object o1 = new Object(); //重新创建 reference = new SoftReference(o); }
弱引用(WeakReference)
当发生GC时,弱引用对象总会被回收,因此弱引用也可以用于缓存。
ThreadLocalMap 防止泄露
监控对象是否将被回收
Object o1 = new Object(); //创建弱引用 WeakReference<Object> wr = new WeakReference<>(o1); wr.get();//有时会返回空 wr.isEnqueued();//返回是否被垃圾回收器标记为即将回收的垃圾 System.gc();//通知 wr.get();//返回null
虚引用(PhantomReference)
主要用来跟踪对象被垃圾回收器回收的活动 。虚引用必须和队列联合使用,当垃圾回收器准备回收一个对象的时候,如果发现它还有虚引用,就会在回收对象之前,把这个虚引用加入到与之关联的引用队列中。
它允许你知道具体何时引用的对象从内存中移除 。处理类似图片的大文件的情况,当你确定一个图片数据对象应该被回收,你可以利用虚引用来判断这个对象回收只有在继续加载下一张图片,可以避免内存溢出。
虚引用可以避免很多析构时的问题 。finalize 方法可以通过创建强引用指向快被销毁的对象来让这些对象重新复活。然而,一个重写了 finalize 方法的对象如果想要被回收掉,需要经历两个单独的垃圾收集周期。在第一个周期中,某个对象被标记为可回收,进而才能进行析构。
#Java学习# #Java# #学习路径#