zoukankan      html  css  js  c++  java
  • Java四种引用

    Java中提供了一个Reference抽象类,此类定义所有引用对象共有的操作,与垃圾收集器密切配合实现的。主要是为了决定某些对象的生命周期,有利于JVM进行垃圾回收。而继承此类的有四种引用,分别是StrongReference(强引用),SoftReference(软引用),WeakReference(弱引用),PhantomReference(虚引用),强度按照上面的顺序依次减弱。下面来看下四种引用的对比。

    类型 调用方式 回收条件 内存泄漏
    StrongReference 直接调用 不回收 可能
    StrongReference get()方法 视内存情况回收 不可能
    WeakReference get()方法 永远回收 不可能
    PhantomReference 无法取得 不回收 可能
    • 强引用
    Object object = new Object()
    

    上面这段代码就是一个强引用,是最普通的引用,当内存空间不足, Java 虚拟机宁愿抛出 OutOfMemoryError 错误,使程序异常终止, 也不会靠随意回收具有强引用的对象来解决内存不足的问。如果想中断或者回收强引用,可以设置引用为null,如object =null,这样的话JVM就会在合适的时间,进行垃圾回收。可以看下下面代码和运行情况。

    private static void strongTest() {
        printlnMemory("Init");
        // 申请5MB的内存
        byte[] strong = new byte[5 * MB];
        printlnMemory("Use 5MB");
        // 回收
        System.gc();
        printlnMemory("GC after");
        System.out.println("gc strong:" + strong);
        // 设置引用为null
        strong = null;
        printlnMemory("set null");
        System.out.println("set null strong:" + strong);
        // 回收
        System.gc();
        printlnMemory("null GC after");
        System.out.println("gc strong:" + strong);
    }
    

    运行情况:

    Init:240M(free)/245M(total)
    
    Use 5MB:235M(free)/245M(total)// 使用了5MB内存
    
    GC after:237M(free)/245M(total)// 释放一些内存
    gc strong:[B@7ea987ac
    
    set null:237M(free)/245M(total)// 强引用设置为null后,内存不变
    set null strong:null
    
    null GC after:242M(free)/245M(total)//强引用设置为null后,回收5MB内存
    gc strong:null
    
    • 软引用
    SoftReference<Object> soft = new SoftReference(new Object());
    

    若一个对象只有软引用,则当空间不足的时候才会回收它,可以用来构建敏感数据的缓存(如网页缓存、图片缓存等)。软引用可以和一个引用队列一同使用,当所引用的对象被回收,软引用便被加入到引用队列。可以看下下面代码和运行情况。

    private static void softTest() {
        printlnMemory("Init");
        SoftReference<byte[]> soft = new SoftReference<>(new byte[2000 * MB]);// 申请2000MB的内存
        printlnMemory("Use 2000MB");
    
        System.gc();// gc回收
        printlnMemory("GC after");
        System.out.println("gc soft:" + soft.get());
    
        SoftReference<byte[]> soft2 = new SoftReference<>(new byte[2000 * MB]);// 再次申请2000MB的内存
        printlnMemory("use after");
        System.out.println("gc soft:" + soft.get());
    }
    

    运行情况

    Init:239M(free)/245M(total)
    
    Use 2000MB:239M(free)/2246M(total)//总内存变大了
    
    GC after:243M(free)/2246M(total) //内存足够没有回收
    gc soft:[B@2db0f6b2
    
    use after:471M(free)/2474M(total)//内存不够,自动回收
    gc soft:null
    
    • 弱引用
    WeakReference<Object> soft = new WeakReference<>(new Object());
    

    弱引用用来描述非必需对象的,当JVM进行垃圾回收时,无论内存是否充足,都会回收被弱引用关联的对象。也可以用来构建敏感数据的缓存,如用于生命周期更短的,对内存更敏感的场景中,比如占用内存很大的Map,java提供了WeakHashMap。可以看下下面代码和运行情况

    private static void weakTest() {
        printlnMemory("Init");
        WeakReference<byte[]> weak= new WeakReference<>(new byte[10 * MB]);
        printlnMemory("Use 10MB");
    
        System.gc();
        printlnMemory("GC after");
        System.out.println("gc weak:" + weak.get());
    }
    

    运行情况

    Init:239M(free)/245M(total)
    
    Use 10MB:229M(free)/245M(total)
    
    GC after:243M(free)/245M(total)//不管内存是否充足,都进行回收
    gc soft:null //weak.get无法再回去对象
    
    • 虚引用
    ReferenceQueue<Object> queue = new ReferenceQueue<Object>();
    PhantomReference<Object> phantom = new PhantomReference<Object>(new Object(), queue);
    

    若一个对象拥有虚引用,则在任何时候都可能被回收。虚引用必须和引用队列联合使用,当所引用的对象被回收,虚引用便被加入到引用队列,主要用来追踪垃圾回收过程。

    private static void phantomTest() {
        printlnMemory("Init");
        byte[] bytes = new byte[5 * MB];
        ReferenceQueue<Object> queue = new ReferenceQueue<Object>();
        PhantomReference<Object> phantom = new PhantomReference<Object>(bytes, queue);
        printlnMemory("Use 5MB");
        System.out.println("phantom : " + phantom);
        System.out.println("phantom.get() : " + phantom.get());
        System.out.println("queue.poll() : " + queue.poll());
        //断开强引用
        bytes = null;
        System.gc();
        printlnMemory("GC after bytes");
        System.out.println("phantom : " + phantom);
        System.out.println("phantom.get() : " + phantom.get());
        System.out.println("queue.poll() : " + queue.poll());
    
        //断开虚引用
        phantom = null;
        System.gc();
        printlnMemory("GC after phantom");
        System.out.println("phantom : " + phantom);
        System.out.println("queue.poll() : " + queue.poll());
    }
    

    运行情况

    Init:239M(free)/245M(total)
    
    Use 5MB:234M(free)/245M(total)
    phantom : java.lang.ref.PhantomReference@2db0f6b2
    phantom.get() : null
    queue.poll() : null
    
    GC after bytes:238M(free)/245M(total)
    phantom : java.lang.ref.PhantomReference@2db0f6b2
    phantom.get() : null
    queue.poll() : java.lang.ref.PhantomReference@2db0f6b2
    
    GC after phantom:243M(free)/245M(total)
    phantom : null
    queue.poll() : null
    
    • ReferenceQueue

    顾名思义存放引用的队列,保存的是Reference对象,其作用在于Reference对象所引用的对象被GC回收时,该Reference对象将会被加入引用队列中的队列末尾。

    常用的方法:

    • poll():从队列中取出一个元素,队列为空则返回null
    • remove():从队列中出对一个元素,若没有则阻塞至有可出队元素
    • remove(long timeout):从队列中出对一个元素,若没有则阻塞至有可出对元素或阻塞至超过timeout毫秒;

    可以看下下面代码

    byte[] bytes = new byte[5 * MB];
    ReferenceQueue<Object> queue = new ReferenceQueue<Object>();
    PhantomReference<Object> phantom = new PhantomReference<Object>(bytes, queue);
    

    这段代码中,对于byte对象有两种引用类型,一是bytes 的强引用,二是phantom 的虚引用。当bytes 被回收时,phantom 所引用的对象将会被放到queue 的队列末尾。利用ReferenceQueue可以清除失去了虚引用对象的引用。

  • 相关阅读:
    php 中ASCII编码的使用
    BASE64
    微信公众平台--6.JS-SDK 微信内网页开发工具包
    python3中zipfile模块的常用方法
    python3开发进阶-Django框架学习前的小项目(一个简单的学员管理系统)
    python3开发进阶-Django框架的起飞加速一(ORM)
    python3开发进阶-Django框架起飞前的准备
    python3开发进阶-Web框架的前奏
    前端基础-jQuery的最常用的的方法each、data、
    前端基础-jQuery的动画效果
  • 原文地址:https://www.cnblogs.com/fomin/p/10254547.html
Copyright © 2011-2022 走看看