四 强/软/弱/虚 引用

  1. 四种引用, 除了基本数据类型外,其他的都是指向各类对象的对象引用
  • 强引用 strong
    通过关键字new创建的对象所关联的引用就是强引用。 当JVM内存空间不足,JVM宁愿抛出OutOfMemoryError运行时错误(OOM),使程序异常终止,也不会靠随意回收具有强引用的“存活”对象来解决内存不足的问题。对于一个普通的对象,如果没有其他的引用关系,只要超过了引用的作用域或者显式地将相应(强)引用赋值为 null,就是可以被垃圾收集的了,具体回收时机还是要看垃圾收集策略。

  • 软引用 soft
    软引用通过SoftReference类实现。 软引用的生命周期比强引用短一些。只有当 JVM 认为内存不足时,才会去试图回收软引用指向的对象:即JVM 会确保在抛出 OutOfMemoryError 之前,清理软引用指向的对象。软引用可以和一个引用队列(ReferenceQueue)联合使用,如果软引用所引用的对象被垃圾回收器回收,Java虚拟机就会把这个软引用加入到与之关联的引用队列中。后续,我们可以调用ReferenceQueue的poll()方法来检查是否有它所关心的对象被回收。如果队列为空,将返回一个null,否则该方法返回队列中前面的一个Reference对象。
    应用场景:软引用通常用来实现内存敏感的缓存。如果还有空闲内存,就可以暂时保留缓存,当内存不足时清理掉,这样就保证了使用缓存的同时,不会耗尽内存。

String str=new String("abc");     // 强引用
 SoftReference softRef=new SoftReference(str);     // 软引用
str = null;
System.out.println(softRef.get());  //abc
//小例子
Browser prev = new Browser();               // 获取到的页面内容
SoftReference sr = new SoftReference(prev); // 浏览完毕后置为软引用,其可达状态变为soft
if(sr.get()!=null){ 
    rev = (Browser) sr.get();           // 之后再查看 还没有被回收器回收,直接获取
}else{
    prev = new Browser();               // 由于内存吃紧,所以对软引用的对象回收了
    sr = new SoftReference(prev);       // 重新构建
}
  • 弱引用 weak
    弱引用通过WeakReference类实现。 弱引用的生命周期比软引用短。在垃圾回收器线程扫描它所管辖的内存区域的过程中,一旦发现了具有弱引用的对象,不管当前内存空间足够与否,都会回收它的内存。由于垃圾回收器是一个优先级很低的线程,因此不一定会很快回收弱引用的对象。弱引用可以和一个引用队列(ReferenceQueue)联合使用,如果弱引用所引用的对象被垃圾回收,Java虚拟机就会把这个弱引用加入到与之关联的引用队列中。
    应用场景:弱应用同样可用于内存敏感的缓存. 例如,一个类发送网络请求,承担callback的静态内部类,则常以虚引用的方式来保存外部类(宿主类)的引用,当外部类需要被JVM回收时,不会因为网络请求没有及时回来,导致外部类不能被回收,引起内存泄漏

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

  1. 所有引用类型都是抽象类java.lang.ref.Reference的子类 它提供了get方法, 返回引用指向的对象. 除了幻象引用(其get永远返回null), 如果对象还没被回收, 都可以通过get方法获取原有对象. 这意味这我们可以以此将软引用弱引用访问到的对象重新指向为强引用, 人为改变可达性状态. 但如果我们错误的保持了强引用(比如赋值给了一个static变量), 那么对象可能就不再有机会变为类似弱引用的状态了, 本来该回收的就不能回收, 即产生内存泄漏

  2. 引用队列
    Reference类构造函数提供了一个ReferenceQueue类型的参数传入,通过提供这个参数,我们便把创建的弱引用对象注册到了一个引用队列上,这样当它被垃圾回收器清除时,就会把它送入这个引用队列中,我们便可以对这些被清除的弱引用对象进行统一管理。

public class ReferenceTest {
 
    private static ReferenceQueue rq = new ReferenceQueue();
 
    public static void checkQueue() {
        Reference ref = null;
        while ((ref = rq.poll()) != null) {
            if (ref != null) {
                System.out.println("In queue: " + ((VeryBigWeakReference) (ref)).id);
            }
        }
    }
 
    public static void main(String args[]) {
        int size = 3;
        LinkedList> weakList = new LinkedList>();
        for (int i = 0; i < size; i++) {
            weakList.add(new VeryBigWeakReference(new VeryBig("Weak " + i), rq));
            System.out.println("Just created weak: " + weakList.getLast());
 
        }
 
        System.gc(); 
        try { // 下面休息几分钟,让上面的垃圾回收线程运行完成
            Thread.currentThread().sleep(6000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        checkQueue();
    }
}
 
class VeryBig {
    public String id;
    // 占用空间,让线程进行回收
    byte[] b = new byte[2 * 1024];
 
    public VeryBig(String id) {
        this.id = id;
    }
 
    protected void finalize() {
        System.out.println("Finalizing VeryBig " + id);
    }
}
 
class VeryBigWeakReference extends WeakReference {
    public String id;
 
    public VeryBigWeakReference(VeryBig big, ReferenceQueue rq) {
        super(big, rq);
        this.id = big.id;
    }
 
    protected void finalize() {
        System.out.println("Finalizing VeryBigWeakReference " + id);
    }
}
//结果
Just created weak: VeryBigWeakReference@63961c42
Just created weak: VeryBigWeakReference@65b54208
Just created weak: VeryBigWeakReference@1be6f5c3
Finalizing VeryBig Weak 2
Finalizing VeryBig Weak 1
Finalizing VeryBig Weak 0
In queue: Weak 1
In queue: Weak 2
In queue: Weak 0
  1. 对象可达性流转分析


    图片.png

你可能感兴趣的:(四 强/软/弱/虚 引用)