zoukankan      html  css  js  c++  java
  • java强引用,软引用,弱引用,虚引用

    java强引用,软引用,弱引用,虚引用

    原文:https://blog.csdn.net/liaodehong/article/details/52223354 

    用了Java怎么长时间一直不知道原来Java还有四种引用类型,这个引用类型和我们平常说的可不一样。这里的引用类型不是指数据类型的一种,而是指Java中的引用所分的四种类型。他们代表了JVM回收内存的四种强度,分别如下。

    强引用:
    Java中的引用,有点像C++的指针。通过引用,可以对堆中的对象进行操作。在某函数中,当创建了一个对象,该对象被分配在堆中,通过这个对象的引用才能对这个对象进行操作。

    Object o = new Object();

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

    如果再创建一个赋值语句

    Object oj = o;

    那么o指向的Object内存空间也会被oj所指向,此时我们可以说oj==o,那么ob.equals也肯定相等,即两个对象的值也肯定一样,当修改了o对象的时候,oj对象也会发生变化,或者当修改了oj对象的时候o对象也肯定会变化。所以如果想复制另外一个对象的值的话千万不要用这种方式,在多线程的情况下可能会有更槽糕的情况发生,你可以使用JDK自带的克隆方法,也可以重写克隆方法。

    public class Test1 {
                public static void main(String[] args) {
                    student S=new student("1","我是大s");
                    student s=S;
                    System.out.println(s==S); //true
                    System.out.println(s.equals(S)); //true
                    System.out.println("打印出大S"+S); //id=1
                    System.out.println("打印出小s"+s); //id=1
                    S.setId("2");
                    System.out.println("修改后的大S"+S);  //id=2
                    System.out.println("未修改后的小s"+s); //id=2
                    s.setId("3");
                    System.out.println("未修改后的大S"+S); //id=3
                    System.out.println("修改后的小s"+s); //id=3
        
                }
    }
    class student{
        String name;
        String id;
        public String getName() {
            return name;
        }
        public void setName(String name) {
            this.name = name;
        }
        public String getId() {
            return id;
        }
        public void setId(String id) {
            this.id = id;
        }
        public student(String name, String id) {
            super();
            this.name = name;
            this.id = id;
        }
        @Override
        public String toString() {
            return "student [name=" + name + ", id=" + id + "]";
        }
        
        
    }

    上例中的大S和小S都是强引用,强引用具有如下特点:

    1.强引用可以直接访问目标对象。

    2.强引用所指向的对象在任何时候都不会被系统回收。JVM宁愿抛出OOM异常,也不会回收强引用所指向的对象。

    3.强引用可能导致内存泄漏,为了避免内存泄漏,在使用完成之后我们可以把字符串对象设置为null,如果是集合的话可以使用

    List list=new ArrayList<>();
    list.clear();

    软引用:
    软引用的强度是仅次于强引用的,如果一个对象只具有软引用,则内存空间足够,垃圾回收器就不会回收它;如果内存空间不足了,就会回收这些对象的内存。只要垃圾回收器没有回收它,该对象就可以被程序使用。软引用可用来实现内存敏感的高速缓存。   

    我们可以使用java.lang.ref.SoftReference来创建软引用;

    String str=new String("abc");                                     // 强引用
    SoftReference<String> softRef=new SoftReference<String>(str);     // 软引用

    当内存不足时,等价于:

    If(JVM.内存不足()) {
       str = null;  // 转换为空引用
       System.gc(); // 垃圾回收器进行回收
    }

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

    如果这个对象是偶尔的使用,并且希望在使用时随时就能获取到,但又不想影响此对象的垃圾收集,那么你应该用 Weak Reference 来标记此对象。

    String str=new String("abc");    
    WeakReference<String> abcWeakRef = new WeakReference<String>(str);
    str=null;

    如果你想把这个对象变成强引用的话可以使用

    String  abc = abcWeakRef.get();

    弱引用可以和一个引用队列(ReferenceQueue)联合使用,如果弱引用所引用的对象被垃圾回收,Java虚拟机就会把这个弱引用加入到与之关联的引用队列中。

    当你想引用一个对象,但是这个对象有自己的生命周期,你不想介入这个对象的生命周期,这时候你就是用弱引用。

    这个引用不会在对象的垃圾回收判断中产生任何附加的影响。

    public class ReferenceTest {
     
        private static ReferenceQueue<VeryBig> rq = new ReferenceQueue<VeryBig>();
     
        public static void checkQueue() {
            Reference<? extends VeryBig> 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<WeakReference<VeryBig>> weakList = new LinkedList<WeakReference<VeryBig>>();
            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<VeryBig> {
        public String id;
     
        public VeryBigWeakReference(VeryBig big, ReferenceQueue<VeryBig> rq) {
            super(big, rq);
            this.id = big.id;
        }
     
        protected void finalize() {
            System.out.println("Finalizing VeryBigWeakReference " + id);
        }
    }

    虚引用
    虚引用顾名思义就是形同虚设,虚引用也称为幻影引用:一个对象是都有虚引用的存在都不会对生存时间都构成影响,也无法通过虚引用来获取对一个对象的真实引用。唯一的用处:能在对象被GC时收到系统通知,JAVA中用PhantomReference来实现虚引用。

    对比不同:

    import java.lang.ref.Reference;
    import java.lang.ref.SoftReference;
    import java.lang.ref.WeakReference;
    import java.lang.ref.PhantomReference;
    import java.lang.ref.ReferenceQueue;
    import java.util.Set;
    import java.util.HashSet;
    
    class Grocery {
        private static final int SIZE = 10000;
        // 属性d使得每个Grocery对象占用较多内存,有80K左右
        private double[] d = new double[SIZE];
        private String id;
        public Grocery(String id) {
            this.id = id;
        }
        public String toString() {
            return id;
        }
        /* public void finalize() { // 注意: finalize 在 Java 11 中已经被废弃
            System.out.println("即将回收 " + id);
        } */
    }
    
    public class HelloWorld {
    
        // 关联的引用队列 如果引用的对象被JVM回收 则这个引用就会被加入到与之关联的引用队列中
        private static ReferenceQueue<Grocery> rq = new ReferenceQueue<Grocery>();
    
        public static void checkQueue() {
    
            boolean flag = true;
            System.out.println(">>>>>>>>>>>>>>>>>>>>");
            while (flag) {
                Reference<? extends Grocery> inq = rq.poll(); // 从队列中取出一个引用
                if (inq != null) {
                    flag = true;
                    System.out.println("In queue: type ===> " + inq + " value ===> " + inq.get());
                } else {
                    flag = false;
                    System.out.println("In queue: " + "is null");
                }
            }
            System.out.println("<<<<<<<<<<<<<<<<<<<");
        }
    
        public static void main(String[] args) {
            // 引用创建的固定数量
            final int size = 10;
    
            // 创建10个Grocery对象以及10个软引用
            Set<SoftReference<Grocery>> sa = new HashSet<SoftReference<Grocery>>();
            for (int i = 0; i < size; i++) {
                SoftReference<Grocery> ref = new SoftReference<Grocery>(
                        new Grocery("SoftReference " + i), rq);
                System.out.println("刚刚 创建了 软引用: " + ref.get());
                sa.add(ref);
            }
            System.gc();
            checkQueue();
    
            // 创建10个Grocery对象以及10个弱引用
            Set<WeakReference<Grocery>> wa = new HashSet<WeakReference<Grocery>>();
            for (int i = 0; i < size; i++) {
                WeakReference<Grocery> ref = new WeakReference<Grocery>(
                        new Grocery("WeakReference " + i), rq);
                System.out.println("刚刚 创建了 弱引用: " + ref.get());
                wa.add(ref);
            }
            System.gc();
            checkQueue();
    
            // 创建10个Grocery对象以及10个虚引用
            Set<PhantomReference<Grocery>> pa = new HashSet<PhantomReference<Grocery>>();
            for (int i = 0; i < size; i++) {
                PhantomReference<Grocery> ref = new PhantomReference<Grocery>(
                        new Grocery("PhantomReference " + i), rq);
                System.out.println("刚刚 创建了 虚引用 : " + ref.get());
                pa.add(ref);
            }
            System.gc();
            checkQueue();
        }
    }

    控制台输出

    >javac -encoding utf-8 -d .src .srcHelloWorld.java
    >java -Dfile.encoding=utf-8 -cp .src HelloWorld
    刚刚 创建了 软引用: SoftReference 0
    刚刚 创建了 软引用: SoftReference 1
    刚刚 创建了 软引用: SoftReference 2
    刚刚 创建了 软引用: SoftReference 3
    刚刚 创建了 软引用: SoftReference 4
    刚刚 创建了 软引用: SoftReference 5
    刚刚 创建了 软引用: SoftReference 6
    刚刚 创建了 软引用: SoftReference 7
    刚刚 创建了 软引用: SoftReference 8
    刚刚 创建了 软引用: SoftReference 9
    >>>>>>>>>>>>>>>>>>>>
    In queue: is null
    <<<<<<<<<<<<<<<<<<<
    刚刚 创建了 弱引用: WeakReference 0
    刚刚 创建了 弱引用: WeakReference 1
    刚刚 创建了 弱引用: WeakReference 2
    刚刚 创建了 弱引用: WeakReference 3
    刚刚 创建了 弱引用: WeakReference 4
    刚刚 创建了 弱引用: WeakReference 5
    刚刚 创建了 弱引用: WeakReference 6
    刚刚 创建了 弱引用: WeakReference 7
    刚刚 创建了 弱引用: WeakReference 8
    刚刚 创建了 弱引用: WeakReference 9
    >>>>>>>>>>>>>>>>>>>>
    In queue: type ===> java.lang.ref.WeakReference@de0a01f value ===> null
    In queue: type ===> java.lang.ref.WeakReference@ba4d54 value ===> null
    In queue: type ===> java.lang.ref.WeakReference@4c75cab9 value ===> null
    In queue: type ===> java.lang.ref.WeakReference@6aceb1a5 value ===> null
    In queue: type ===> java.lang.ref.WeakReference@769c9116 value ===> null
    In queue: type ===> java.lang.ref.WeakReference@1ef7fe8e value ===> null
    In queue: type ===> java.lang.ref.WeakReference@12bc6874 value ===> null
    In queue: type ===> java.lang.ref.WeakReference@2d6d8735 value ===> null
    In queue: type ===> java.lang.ref.WeakReference@67117f44 value ===> null
    In queue: type ===> java.lang.ref.WeakReference@6f79caec value ===> null
    In queue: is null
    <<<<<<<<<<<<<<<<<<<
    刚刚 创建了 虚引用 : null
    刚刚 创建了 虚引用 : null
    刚刚 创建了 虚引用 : null
    刚刚 创建了 虚引用 : null
    刚刚 创建了 虚引用 : null
    刚刚 创建了 虚引用 : null
    刚刚 创建了 虚引用 : null
    刚刚 创建了 虚引用 : null
    刚刚 创建了 虚引用 : null
    刚刚 创建了 虚引用 : null
    >>>>>>>>>>>>>>>>>>>>
    In queue: type ===> java.lang.ref.PhantomReference@2cfb4a64 value ===> null
    In queue: type ===> java.lang.ref.PhantomReference@5474c6c value ===> null
    In queue: type ===> java.lang.ref.PhantomReference@7a92922 value ===> null
    In queue: type ===> java.lang.ref.PhantomReference@483bf400 value ===> null
    In queue: type ===> java.lang.ref.PhantomReference@71f2a7d5 value ===> null
    In queue: type ===> java.lang.ref.PhantomReference@4b6995df value ===> null
    In queue: type ===> java.lang.ref.PhantomReference@21a06946 value ===> null
    In queue: type ===> java.lang.ref.PhantomReference@326de728 value ===> null
    In queue: type ===> java.lang.ref.PhantomReference@77f03bb1 value ===> null
    In queue: type ===> java.lang.ref.PhantomReference@25618e91 value ===> null
    In queue: is null
    <<<<<<<<<<<<<<<<<<<

    在上面的这个例子中,依次创建了十个10个软引用、10个弱引用和10个虚引用,它们各自引用一个Grocery对象。并且在创建之后调用GC方法。从程序运行时的打印结果可以看出,虚引用形同虚设,它所引用的对象随时可能被垃圾回收,具有弱引用的对象拥有稍微长的生命周期,当垃圾回收器执行回收操作时,有可能被垃圾回收,具有软引用的对象拥有较长的生命周期,但在Java虚拟机认为内存不足的情况下,也会被垃圾回收。

    总结
    强引用:就像是老板(OOM)的亲儿子一样,在公司可以什么事都不干,但是千万不要老是占用公司的资源为他自己做事,记得用完公司的妹子之后,要让她们去工作(资源要懂得释放) 不然公司很可能会垮掉的。
    软引用:有点像老板(OOM)的亲戚,在公司表现不好有可能会被开除,即使你投诉他(调用GC)上班看片,但是只要不被老板看到(被JVM检测到)就不会被开除(被虚拟机回收)。
    弱引用:就是一个普通的员工,平常如果表现不佳会被开除(对象没有其他引用的情况下),遇到别人投诉(调用GC)上班看片,那开除是肯定了(被虚拟机回收)。
    虚引用:这货估计就是个实习生跟临时工把,遇到事情的时候想到了你,没有事情的时候,秒秒钟拿出去顶锅,开除。

    ================= End

  • 相关阅读:
    array_udiff_assoc — 带索引检查计算数组的差集,用回调函数比较数据
    array_sum — 对数组中所有值求和
    array_splice — 去掉数组中的某一部分并用其它值取代
    array_slice — 从数组中取出一段
    array_multisort — 对多个数组或多维数组进行排序
    array_merge — 合并一个或多个数组
    array_keys — 返回数组中部分的或所有的键名
    array_key_exists — 检查数组里是否有指定的键名或索引
    array_intersect_assoc — 带索引检查计算数组的交集
    array_flip — 交换数组中的键和值
  • 原文地址:https://www.cnblogs.com/lsgxeva/p/10215146.html
Copyright © 2011-2022 走看看