Java中强引用、软引用、弱引用、幻象引用有什么区别?

强引用、软引用、弱引用、幻象引用有什么区别?

  在Java语言当中 ,除了原始数据类型之外,其它的都是所谓的引用类型,指向各种不同的对象,理解引用对于掌握Java对象生命周期和JVM内部相关机制非常有帮助。
   不同的引用类型,主要体现的是对象不同的可达性状态和对垃圾回收的影响。下面笔者将会对这4中引用进行详细的解释:
  强引用 : 就是我们最常见的的普通对象引用,只要还有一个强引用指向一个对象,就表明对象还“活着”,垃圾收集器不会碰这种对象。 对于一个普通对象,如果没有其他的引用关系,只要超过了引用的作用域或者显式地将强引用赋值为null,就是可以被垃圾回收器收集了,当然具体回收时机还要看垃圾收集的策略。
  软引用:是一种相对强引用弱化的一些引用,可以让对象豁免一些垃圾收集,只有当JVM认为内存不足的时候,才会去尝试回收软引用指向的对象。JVM会确保在抛出OutOfMemoryError之前,清理软引用指向的对象。软引用通常来实现敏感的的缓存,如果还有空闲的内存,就可以暂时保存缓存,这样就保证了使用缓存的同时,不会耗尽内存。
   弱引用:并不能使对象豁免垃圾收集,仅仅是提供一种访问在弱引用状态下的对象的途径。这就可以用来构建一种没有特定约束的关系,比如,维护一种非强制性的映射关系,如果试图获取时对象还在,就使用它,否则就重新实例化。它同样是很多缓存实现的选择。
  幻象引用:对于幻象引用,有时候也翻译为虚引用 。你不能通过它来访问对象,幻象引用仅仅是提供一种确保对象被finalize后,做某些事情的机制。比如,通常用来做所谓的Post-Mortem清理机制,也有人利用幻象引用监控对象的创建和销毁。
  我想对于以上的4种引用解释,读者肯定有些地方特别懵逼,特别是幻象引用,既然不能通过幻象引用访问对象,那么还要它干嘛呢?很少程序使用除强引用之外的这些引用,由于笔者是Android程序员,一些Android的框架,里面用到这些引用机制,为了能搞懂这些框架,笔者不得不将这4中引用的用法融会贯通,下面跟随笔者一起探究一下它们的用法吧!笔者将会结合JVM GC机制探究。

4种引用的用法:
[1] 强引用的用法
  Object obj1 = new Object();//这种声明方式就是强引用的方式,它的标志就是需要使用new关键字
强引用的标志就是“new”关键字,一般强引用是不会被垃圾收集器碰触到的,除非是作用域范围之外,那么什么是作用域范围之外呢?请看以下代码:

public void methondA(String a){

    ......
    Student student = new Student(a);
    ......

}

  上述代码是一个方法的代码片段,可以看到student是一个强引用,它的作用域仅仅是这个方法范围之内,当程序运行完这个方法之后,这个强引用student指向的对象就会无效了,换言之,无效的对象当然是回收为好啦,于是JVM便把它回收了。但是如果你把它返回了呢,比如以下代码:

public Student methondA(String a){

    ......
    Student student = new Student(a);
    ......
    return student;//这里返回了student    
}

[2] 软引用用法
  软引用通过SoftReference类来实现。软引用的生命周期比强引用短一些。软引用可以和一个引用队列(ReferenceQueue)联合使用,如果软引用所引用的对象被垃圾回收器回收,Java虚拟机就会把这个软引用加入到与之关联的引用队列中。后续,我们可以调用ReferenceQueue的poll()方法来检查是否有它所关心的对象被回收。如果队列为空,将返回一个null,否则该方法返回队列中前面的一个Reference对象。说了这么多废话,软引用通常用来实现内存敏感的缓存。如果还有空闲内存,就可以暂时保留缓存,当内存不足时清理掉,这样就保证了使用缓存的同时,不会耗尽内存。大概一句话总结:软引用就是为了保证内存资源不会被耗尽,避免出现OutOfMerorError这种不可逆的错误。实例代码如下:

MyObject aRef = new  MyObject();  
SoftReference aSoftRef=new SoftReference(aRef);  
aRef = null;//这是为了去掉对象的强可达

[3] 弱引用用法
  弱引用通过WeakReference类实现。弱引用的生命周期比软引用还要短。在垃圾回收扫描它所管辖的内存区域的过程中,一旦发现了具有弱引用的对象,不管当前内存空间足够与否,都会回收它的内存。由于垃圾回收器是一个优先级很低的线程,因此不一定会很快回收弱引用的对象。弱引用可以和一个引用队列(ReferenceQueue)联合使用,如果弱引用所引用的对象被垃圾回收,Java虚拟机就会把这个弱引用加入与之关联的引用队列中。如果你是Android程序员,你肯定对Handler使用很有体会,为什么要把当前Activity的Context变成弱引用再传递给内部类的Handler呢?我想看到这里你应该非常明白了吧!

这里写图片描述

[4] 幻象引用用法

  幻象引用也叫虚引用,通过PhantomReference类来实现。无法通过虚引用访问对象的任何属性或函数。幻象应用仅仅是提供了一种确保对象被finalize以后,做某些事情的机制。如果一个对象仅持有虚引用,那么它就和没有任何引用一样,在任何时候都有可能被垃圾回收器回收。虚引用必须和引用队列(ReferenceQueue)联合使用。当垃圾回收器准备回收一个对象时,如果发现它还有虚引用,就会在回收对象的内存之前,把这个虚引用与之关联的引用队列中。

Object obj1 = new Object();
ReferenceQueue<Object> referenceQueue = new ReferenceQueue<>();
PhantomReference<Object> phantomReference = new PhantomReference<Object>(obj1, referenceQueue);

猜你喜欢

转载自blog.csdn.net/ClAndEllen/article/details/81187106