zoukankan      html  css  js  c++  java
  • java对象引用-强弱软虚

    一、简述 

      Java对象的四种引用:强软弱虚。通过四种引用的使用,开发者通过代码去决定对象的生命周期,从而有利于JVM的垃圾回收。在各种面试环节中被问及的频率也是相当高的,比如对于弱引用,一般结合到ThreadLocal。除了强引用,其他几种引用都是借助于引用类去完成的。

    二、强引用

      基本上,开发者都是使用的格式,如 Object obj = new Object(); 就是个强引用。一般情况下,只要某个对象有强引用与之关联的,JVM就不会去回收这玩意。即使内存溢出OutOfMemoryError,也不会强制的去回收,只会程序异常终止。

      当然了,如果显式置obj=null ,那么JVM会适时的去回收掉改对象。光说不练假把式,上实验对象:

     1 public class ReferenceTest {
     2 
     3     public static void main(String[] args) {
     4         ReferenceTest referenceTest = new ReferenceTest();
     5         referenceTest = null;
     6         System.gc();
     7     }
     8 
     9     @Override
    10     protected void finalize() throws Throwable {
    11         super.finalize();
    12         System.out.println("回收 ReferenceTest 对象...");
    13     }
    14 }

      实验对象中,重写了 finalize 方法,在对象置为 null 并 手动提醒 GC的时候,打印出结果 “回收 ReferenceTest 对象...”,也就说明资源被回收。当然实际开发中,一般不会去重写 finalize 方法,并且手动的置 null 操作,也是提醒JVM去适时的可回收这部分对象。

      JDK中,如HashMap中的 clear 方法

    public void clear() {
        modCount++;
        Arrays.fill(table, null);
        size = 0;
    }
    public static void fill(Object[] a, Object val) {
        for (int i = 0, len = a.length; i < len; i++)
            a[i] = val;
    }

    三、软引用

      类:SoftReference

      内存不足,触发 GC ,回收完成还不足,再干掉 SoftReference 中包装的对象,也就是说对象的软引用,会根据内存状态来决定是否回收,内存充足,gc即使扫到,也不会处理。相反,内存不足了,那么触发gc,就会回收对象的内存。

      实验对象走一遍

    public class ReferenceTest {
        public static void main(String[] args) {
            SoftReference<byte[]> softReference = new SoftReference<>(new byte[1024 * 1024 * 10]); //10M的byte数组
            System.out.println(softReference.get());
            System.gc();
            System.out.println(softReference.get()); //内存充足,不会被回收,取得到对象
            byte[] bytes = new byte[1024 * 1024 * 10];
            System.out.println(softReference.get());
        }
    }

      程序运行时,设置 JVM 最大堆内存参数 : -Xmx20M ,初始时 SoftReference 包装一个 10M 空间大小的字节数组,后续再申请一个10M大小的空间,内存不足,触发GC,回收掉软引用对象,不然就OOM了。结果如下:

    [B@1b6d3586
    [B@1b6d3586
    null

    四、弱引用

      类:WeakReference

      生命周期很短,理论上两次gc的时间间隔就是存活时间。如果包裹的对象没有外部强引用的时候,不管内存情况,直接回收掉。

    public class ReferenceTest {
    public static void main(String[] args) throws Exception{
    ReferenceTest referenceTest = new ReferenceTest();
    WeakReference<ReferenceTest> weakReference = new WeakReference<>(referenceTest);

    System.out.println(weakReference.get());

    System.gc();
    System.out.println(weakReference.get());

    referenceTest = null;
    System.gc();
    System.out.println(weakReference.get());

    }
    }

      运行结果:

      com.cfang.reference.ReferenceTest@12a3a380
      com.cfang.reference.ReferenceTest@12a3a380
      null

      可以看出,内存充足情况下,触发GC的时候,对象资源还是被回收掉了。常见的JDK中使用: ThreadLocal。

    五、虚引用

      类:PhantomReference

      幽灵引用,一般结合着 ReferenceQueue 使用,在GC的时候,对象资源被回收并且此对象的虚引用被放到队列中。上实验对象:

    public class ReferenceTest {
    
        public static void main(String[] args) throws Exception{
           ReferenceQueue queue = new ReferenceQueue();
           PhantomReference<ReferenceTest> phantomReference = new PhantomReference<>(new ReferenceTest(), queue);
    
           List<byte[]> list = Lists.newArrayList();
           new Thread(() -> {
               for (int i = 0; i < 100; i++){
                   System.out.println("第" + i + "次放数据");
                   list.add(new byte[1024 * 1024 * 1]);
               }
           }).start();
    
            new Thread(() -> {
                while (true){
                   Reference reference = queue.poll();
                   if(null != reference){
                       System.out.println("虚应用被回收..." + reference);
                   }
                }
            }).start();
    
            Thread.currentThread().join();
        }
    
        @Override
        protected void finalize() throws Throwable {
            System.out.println("回收 ReferenceTest 对象...");
        }
    }

      实验中,第一个线程去申请内存空间并加到集合中,随着次数的累计,必然发生GC。第二个线程中,循环去获取队列数据。从最终运行结果上看,发生GC的时候,虚引用对象被回收掉,并且虚引用被放到队列中去。

    第0次放数据
    第1次放数据
    第2次放数据
    回收 ReferenceTest 对象...
    第3次放数据
    虚应用被回收...java.lang.ref.PhantomReference@5c4497a5
    Exception in thread "Thread-0" java.lang.OutOfMemoryError: Java heap space
        at com.cfang.reference.ReferenceTest.lambda$main$0(ReferenceTest.java:23)
        at com.cfang.reference.ReferenceTest$$Lambda$1/363771819.run(Unknown Source)
        at java.lang.Thread.run(Thread.java:748)
  • 相关阅读:
    【Sparse】关于__attribute__((bitwise)),__le32,__be32等的理解【转】
    设备树中ranges属性分析(1)【转】
    Linux内核API sprint_symbol【转】
    Linux内核--网络协议栈深入分析(二)--sk_buff的操作函数【转】
    浅析SkipList跳跃表原理及代码实现【转】
    关于kernel module签名【转】
    apt-get 更新指定软件_Linux系统 aptget 命令的使用:安装、更新、卸载软件包【转】
    如何挂载ubi文件系统【转】
    伙伴系统之伙伴系统概述--Linux内存管理(十五)【转】
    精确时间协议PTP研究【转】
  • 原文地址:https://www.cnblogs.com/eric-fang/p/10310399.html
Copyright © 2011-2022 走看看