zoukankan      html  css  js  c++  java
  • Java中的四种引用类型

    引用与对象

      每种编程语言都有自己操作内存中元素的方式,例如在 C 和 C++ 里是通过指针,而在 Java 中则是通过“引用”。在 Java 中一切都被视为了对象,但是我们操作的标识符实际上是对象的一个引用(reference)。

      从JDK 1.2版本开始,把对象的引用分为4种级别,从而使程序能更加灵活地控制对象的生命周期。这4种引用的强度依次减弱:强引用(Strong Reference)、软引用(Soft Reference)、弱引用(Weak Reference)、虚引用(Phantom Reference)4 种。

    //创建一个引用,引用可以独立存在,并不一定需要与一个对象关联
    String s;
    
    //通过这个引用标识符指向某个对象,之后便可以通过这个引用来实现操作对象了。
    s = new String("abc");
    System.out.println(str.toString());

      Java 中的垃圾回收机制在判断是否回收某个对象的时候,都需要依据“引用”这个概念。
      在不同垃圾回收算法中,对引用的判断方式有所不同:

      • 引用计数法:为每个对象添加一个引用计数器,每当有一个引用指向它时,计数器就加1,当引用失效时,计数器就减1,当计数器为0时,则认为该对象可以被回收(目前在Java中已经弃用这种方式了)。
      • 可达性分析算法:从一个被称为 GC Roots 的对象开始向下搜索,如果一个对象到GC Roots没有任何引用链相连时,则说明此对象不可用。

      

    引用类型

      1、强引用

      Java中默认声明的就是强引用,只要强引用存在,垃圾回收器将永远不会回收被引用的对象,哪怕内存不足时,JVM也只会直接抛出OutOfMemoryError,不会去回收。如果想中断强引用与对象之间的联系,可以显示的将强引用赋值为null,这样一来,JVM就可以适时的回收对象了。例如:

            //只要obj还指向Object对象,Object对象就不会被回收
            Object obj = new Object();
            
            //将强引用赋值为null后JVM可以回收
            obj = null;

      2、软引用

      软引用是用来描述一些非必需但仍有用的对象。在内存足够的时候,软引用对象不会被回收,只有在内存不足时,GC则会回收软引用对象,如果回收了软引用对象之后仍然没有足够的内存,才会抛出内存溢出异常。这种特性常常被用来实现缓存技术,比如网页缓存,图片缓存等。在 JDK1.2 之后,用java.lang.ref.SoftReference类来表示软引用。

      接下来做个测试,我的内存配置如下图:

    软引用:

    public static void testSoftReference() {
            for (int i = 0; i < 5; i++) {
                //创建弱引用字节数组
                byte[] buff = new byte[1024 * 1024 * 1000];
                SoftReference<byte[]> sr = new SoftReference<byte[]>(buff);
                list.add(sr);
            }
    
            //主动通知垃圾回收,内存不足时回收弱引用
            System.gc();
    
            for(int i=0; i < list.size(); i++){
                Object obj = ((SoftReference) list.get(i)).get();
                System.out.println(obj);
            }
        }
    测试结果:
    null
    null null null [B@14ae5a5

      打印结果总是只有最后一个对象被保留,其他的obj全都被置空回收了。这里就说明了在内存不足的情况下,软引用将会被自动回收。即使有 byte[] buff 引用指向对象, 且 buff 是一个strong reference, 但是 SoftReference sr 指向的对象仍然被回收了,这是因为Java的编译器发现了在之后的代码中, buff 已经没有被使用了, 所以自动进行了优化。

    强引用:

    public static void testSoftReference1() {
            //强引用
            byte[] buff = null;
    
            for (int i = 0; i < 5; i++) {
                buff = new byte[1024 * 1024 * 1000];
                SoftReference<byte[]> sr = new SoftReference<byte[]>(buff);
                list.add(sr);
            }
    
            //主动通知垃圾回收,内存不足时回收弱引用
            System.gc();
    
            for(int i=0; i < list.size(); i++){
                Object obj = ((SoftReference) list.get(i)).get();
                System.out.println(obj);
            }
        }
    结果:
    Exception in thread "main" java.lang.OutOfMemoryError: Java heap space at com.demo.ReferenceTest.testSoftReference1(ReferenceTest.java:45) at com.demo.ReferenceTest.main(ReferenceTest.java:20)

    buff 会因为强引用的存在,而无法被垃圾回收,从而抛出OOM的错误。

      3.弱引用

      弱引用的引用强度比软引用要更弱一些,无论内存是否足够,只要 JVM 开始进行垃圾回收,那些被弱引用关联的对象都会被回收。在 JDK1.2 之后,用 java.lang.ref.WeakReference 来表示弱引用。

    public static void testWeakReference() {
            for (int i = 0; i < 5; i++) {
                byte[] buff = new byte[1024 * 1024 * 1000];
                WeakReference<byte[]> sr = new WeakReference<byte[]>(buff);
                list.add(sr);
            }
    
            //主动通知垃圾回收
            System.gc();
    
            for(int i=0; i < list.size(); i++){
                Object obj = ((WeakReference) list.get(i)).get();
                System.out.println(obj);
            }
        }
    结果:
    null
    null null null null

    可以发现所有被弱引用关联的对象都被垃圾回收了。

      弱引用与软引用的区别在于:只具有弱引用的对象拥有更短暂的生命周期。在垃圾回收器线程扫描它所管辖的内存区域的过程中,一旦发现了只具有弱引用的对象,不管当前内存空间足够与否,都会回收它的内存。不过,由于垃圾回收器是一个优先级很低的线程,因此不一定会很快发现那些只具有弱引用的对象。

      4、虚引用

       (1)概念

      “虚引用”顾名思义,就是形同虚设,与其他几种引用都不同,虚引用并不会决定对象的生命周期。如果一个对象仅持有虚引用,那么它就和没有任何引用一样,在任何时候都可能被垃圾回收器回收。

      虚引用主要用来跟踪对象被垃圾回收器回收的活动。虚引用与软引用和弱引用的一个区别在于:虚引用必须和引用队列 (ReferenceQueue)联合使用。当垃圾回收器准备回收一个对象时,如果发现它还有虚引用,就会在回收对象的内存之前,把这个虚引用加入到与之 关联的引用队列中。

    public class PhantomReference<T> extends Reference<T> {
        /**
         * Returns this reference object's referent.  Because the referent of a
         * phantom reference is always inaccessible, this method always returns
         * <code>null</code>.
         *
         * @return  <code>null</code>
         */
        public T get() {
            return null;
        }
        public PhantomReference(T referent, ReferenceQueue<? super T> q) {
            super(referent, q);
        }
    }

      (2)引用队列(ReferenceQueue)

      引用队列可以与软引用、弱引用以及虚引用一起配合使用,当垃圾回收器准备回收一个对象时,如果发现它还有引用,那么就会在回收对象之前,把这个引用加入到与之关联的引用队列中去。程序可以通过判断引用队列中是否已经加入了引用,来判断被引用的对象是否将要被垃圾回收,这样就可以在对象被回收之前采取一些必要的措施。

      与软引用、弱引用不同,虚引用必须和引用队列一起使用。

    参考地址:https://www.cnblogs.com/liyutian/p/9690974.html

    初心回归,时光已逝!
  • 相关阅读:
    【2、koa】async和await(ES7)
    外部获取异步方法中的数据两种方式callback&Promise
    filter方法
    【ES6】let、var、const
    ubuntu下安装typora
    自我修养之产品思维与能力
    vue
    allure-pytest 测试报告分享给大家
    最近公司遇到了APR攻击,顺便了解一下知识
    Sybase数据库连接配置
  • 原文地址:https://www.cnblogs.com/yin1361866686/p/11044807.html
Copyright © 2011-2022 走看看