• Java的四种引用之强弱软虚


     在java中提供4个级别的引用:强引用、软引用、弱引用和虚引用。除了强引用外,其他3中引用均可以在java.lang.ref包中找到对应的类。开发人员可以在应用程序中直接使用他们。

    1 强引用

    强引用就是程序中一般使用的引用类型,强引用的对象是可触及的,不会被回收。相对的,软引用、弱引用和虚引用的对象是软可触及的、弱可触及的和虚可触及的,在一定条件下,都是可以被回收的。

    强引用示例:StringBuffer str = new StringBuffer("Hello world");

    假设以上代码是在函数体内运行的,那么局部变量str将被分配在栈上,而对象StringBuffer实例被分配在堆上。局部变量str指向StringBuffer实例所在堆空间,通过str可以操作该实例,那么str就是StringBuffer实例的强引用。

    此时,如果再运行一个赋值语句:

    StringBuffer str1 = str;

    则str所指向的对象也将被str1所指向,同时在局部变量表上会分配空间存放str1变量。此时该StringBuffer实例就有两个引用。对引用的“==”操作用于表示两操作数所指向的堆空间地址是否相同,不表示两操作数所指的对象是否相同。

    强引用的特点:

    • 强引用可以直接访问目标对象
    • 强引用所指向的对象在任何时候都不会被系统回收,虚拟机宁愿抛出OOM异常,也不会回收强引用所指的对象。
    • 强引用可能导致内存泄漏

    2 软引用----可被回收的引用

    软引用是比强引用弱一点的引用类型,一个对象只持有软引用,那么当堆空间不足时,就会被回收。软引用使用java.lang.ref.SoftReference类型

    package com.jvm;
    import java.lang.ref.SoftReference;
    public class SoftRef {
      public static class User{
        public User(int id,String name){
          this.id = id;
          this.name = name;
        }
        public int id;
        public String name;
        @Override
        public String toString() {
          return "[id="+String.valueOf(id)+",name="+name+"]";
        }
      }
      public static void main(String[] args) {
        User u = new User(1,"gim");
        SoftReference<User> userSoftRef = new SoftReference<User>(u);//创建引用给定对象的新的软引用
        u = null; //去除强引用

        System.out.println(userSoftRef.get());
        System.gc();
        System.out.println("After GC:");
        System.out.println(userSoftRef.get());

        byte[] b = new byte[1024*925*7];//分配7M左右,使内存空间紧张
        System.gc();
        System.out.println(userSoftRef.get());
      }
    }

    如果虚拟机不加参数设置堆内存限制,则打印出:

    [id=1,name=gim]
    After GC:
    [id=1,name=gim]
    [id=1,name=gim]

    因为虚拟机的内存总量是九十多兆,且虚拟机企图使用的最大内存总量是这个的十几倍。故不会出现资源紧张,也不会产生内存溢出现象。

    如果使用-Xmx10m运行上述代码,可以得到:

    [id=1,name=gim](第一次从软引用中获取数据)
    After GC:
    [id=1,name=gim](GC没有清除软引用)
    null(由于内存紧张,软引用被清除)

    结论:GC未必会回收软引用的对象,但是当内存资源紧张时,软引用对象会被回收,所以软引用对象不会引起内存溢出。

    3 弱引用-----发现即回收

     弱引用是一种比软引用较弱的引用类型。在系统GC时,只要发现弱引用,不管系统堆空间使用情况如何,都会将对象进行回收。但是由于垃圾回收器的优先级通常很低,因此,并不一定能很快的发现持有弱引用的对象。在这种情况下,弱引用对象可以存在较长的时间,一旦一个弱引用对象被垃圾回收器回收,便会加入一个注册的引用队列(这一点和软引用很像)。弱引用使用java.lang.ref.WeakReference类实现。

    实例2:展示弱引用的特点

    package com.jvm;
    import java.lang.ref.WeakReference;
    public class WeakRef {
      public static class User{
        public User(int id,String name){
          this.id = id;
          this.name = name;
        }
        public int id;
        public String name;

        @Override
        public String toString() {
          return "[id="+String.valueOf(id)+",name="+name+"]";
        }
      }

      public static void main(String[] args) {
        User u = new User(1,"gim");
        WeakReference<User> userReference = new WeakReference<User>(u);
        u = null;
        System.out.println(userReference.get());
        System.gc();
        System.out.println("After GC:");
        System.out.println(userReference.get());
      }
    }

    不用设置虚拟机参数,直接运行代码打印出:

    [id=1,name=gim]
    After GC:
    null

    可以看书,GC之后,弱引用对象立即被清除。弱引用和软引用一样,在构造弱引用时,也可以指定一个引用队列,当弱引用对象被回收时,就会加入指定的引用队列,通过这个队列可以跟踪对象的回收情况。

    注意:软引用、弱引用都非常适合来保存那些可有可无的缓存数据(应用场景)。如果这么做,当系统内存不足时,这些缓存数据会被回收,不会导致内存的溢出,而当内存资源充足时,这些缓存又可以存在相当长的时间,从而起到加速系统的作用。

    4 虚引用----对象回收跟踪

     一个持有虚引用的对象,和没有引用几乎一样。随时都可能被垃圾回收器回收,当试图通过虚引用的get()方法取得强引用时,总是会失败。

    并且,虚引用必须和引用队列一起使用,它的作用主要是跟踪垃圾回收过程

    当垃圾回收器准备回收一个对象时,如果发现它还有虚引用,就会在回收对象后,将这个虚引用加入引用队列,以通知引用程序对象的回收情况。

    实例3 :使用虚引用跟踪一个可复活对象的回收

    package com.jvm;

    import java.lang.ref.PhantomReference;
    import java.lang.ref.ReferenceQueue;

    public class TraceCanReliveObj {
      public static TraceCanReliveObj obj;  //可以复活对象
      static ReferenceQueue<TraceCanReliveObj> phantomQueue = null;
      public static class CheckRefQueue extends Thread{
        @Override
        public void run() {
          while(true){
            if(phantomQueue!=null){
              PhantomReference<TraceCanReliveObj> objt = null;
              try{
                objt = (PhantomReference<TraceCanReliveObj>) phantomQueue.remove();
              }catch(InterruptedException e){
                e.printStackTrace();
              }
              if(objt!=null){
                System.out.println("TraceCanReliveObj is delete by GC");
              }
            }
          }
        }
      }

      @Override
      protected void finalize() throws Throwable {
        super.finalize();
        System.out.println("CanReliveObj finalize called");
        obj = this; //使得对象复活
      }
      @Override
      public String toString() {
        return "I am CanReliveObj";
      }
      public static void main(String[] args) throws InterruptedException {
        Thread t = new CheckRefQueue();
        t.setDaemon(true);//守护线程
        t.start();
        phantomQueue = new ReferenceQueue<TraceCanReliveObj>();
        obj = new TraceCanReliveObj();

        //构造了TraceCanReliveObj对象的虚引用,并指定了引用队列。
        PhantomReference<TraceCanReliveObj> phantomRef = new PhantomReference<TraceCanReliveObj>(obj, phantomQueue);
        obj = null;  //将强引用去除
        System.gc();  //第一次进行GC,由于对象可复活,GC无法回收该对象。
        Thread.sleep(1000);
        if(obj==null){
          System.out.println("obj 是 null");
        }else{
          System.out.println("obj 可用");
        }
        System.out.println("第二次GC");
        obj = null;
        System.gc(); //第二次进行GC,由于finalize()只会被调用一次,因此第2次GC会回收对象,同时其引用队列应该也会捕获到对象的回收
        Thread.sleep(1000);
        if(obj==null){
          System.out.println("obj 是 null");
        }else{
          System.out.println("obj 可用");
        }
      }
    }

    直接运行代码打印:

    CanReliveObj finalize called    (对象复活)
    obj 可用
    第二次GC           (第2次,对象无法复活) 
    TraceCanReliveObj is delete by GC (引用队列捕获到对象被回收)
    obj 是 null

    由于虚引用可以跟踪对象的回收时间,因此,也可以将一些资源释放操作放置在虚引用中执行和记录。

  • 相关阅读:
    将来要干啥
    选新技术考虑点
    hdfs 创建一个新用户
    linux下实现mysql数据库定时备份
    PostgreSQL的安装和卸载,远程连接
    PostgreSQL语法
    【NiFi系列】1-基本介绍
    大数据相关资源网址
    MySQL主从复制配置
    MySQL设置免密登录
  • 原文地址:https://www.cnblogs.com/zwbg/p/6196000.html
Copyright © 2020-2023  润新知