你真的了解Java的引用吗?

45 阅读2分钟

知识前置

  • 新生代与老年代
  • 异常处理
  • JVM参数配置

1. 引用(都是可达的)

  • 强引用、软引用、弱引用、虚引用(引用强度逐渐减弱)
  • OOM除了强引用,其它都不会有关系

1.1 强引用(默认引用类型)

  • 传统引用的定义,UserSaveReqVO userSaveReqVO = new UserSaveReqVO()这种的就是强引用。只要强引用关系在,垃圾收集器永远不会回收掉被引用的对象。

1.2 软引用(内存不足即回收)

  • 在系统将要发生OOM之前才会把这些对象列入回收范围中进行第二次回收。如果这次回收后还没有足够的内存,才会OOM。
  • 思考:例如Spring Boot组件内存的缓存是不是可以支持扩展为软引用?
    // -Xms32m -Xmx32m
    // -XX:+PrintGCDetails 想看堆信息的可以加这个参数(更直观)
    // 新生代和老年代大概是1:2
    public static void main(String[] args) {
        // 第一种创建弱引用方式
        SoftReference<Object> softReference1 = new SoftReference<>(new Object());

        // 第二种创建弱引用方式
        Object object = new Object();
        SoftReference<Object> softReference2 = new SoftReference<>(object);
        // 释放强引用
        object = null;

        // 目前GC不会释放对象(堆空间充足)
        System.gc();
        System.out.println(softReference1.get());

        try {
            System.out.println(softReference1.get());
            byte[] bytes = new byte[1024 * 1024 * 22];
        } catch (Throwable throwable) {
            throwable.printStackTrace();
        } finally {
            System.out.println(softReference1.get());
        }
    }
    /**
     * JDK17会略有不同
     * java.lang.Object@18eed359
     * java.lang.Object@18eed359
     * java.lang.OutOfMemoryError: Java heap space
     * 	at com.scaffold.boot.server.Test.main(Test.java:26)
     * null
     */

1.3 弱引用(发现即回收)

  • 当垃圾收集器工作时,无论内存空间是否足够,都会回收掉被弱引用的对象。
    public static void main(String[] args) {
        // 第一种创建弱引用方式
        WeakReference<Object> weakReference1 = new WeakReference<>(new Object());

        // 第二种创建弱引用方式与相同

        System.out.println(weakReference1.get());	// 对象没被释放
        System.gc();

        System.out.println(weakReference1.get());	// null
    }

1.4 虚引用

  • 无法通过虚引用获得一个对象的实例。给对象设置虚引用关联的唯一目的就是能在这个对象被垃圾收集器回收时收到一个系统通知。

TIPS

  • 不要随便在公司的代码里面手动System.gc();