java引用类型

强引用

  • 普通的引用都是强引用
Object o = new Object();
  • 但凡这个对象在任何一个地方被使用,java 的gc 必然不会回收这个对象
  • 就算显式调用了gc 方法也不行,因为jvm 认为这个对象还会被使用
public static void main(String[] args) throws InterruptedException, IOException {
        Object g = 10;
        System.gc();
        System.in.read();
        System.out.println(g);
    }
  • 想要他被回收可以把g设置为null

软引用

  • 当一个对象被一个软引用指定时,只有系统内存不够用时才会回收该对象。
    image-1651905630097
public static void main(String[] args) throws InterruptedException, IOException {
        SoftReference soft = new SoftReference(new byte[1024 * 1024 * 30]);
        System.out.println(soft.get());
        System.gc();
        Thread.sleep(1000);
        byte[] b =  new byte[1024 * 1024 * 15];
        System.out.println(soft.get());
    }

image-1651905650936

  • 如上他被回收了
  • 他需要被SoftReference 包装
  • 主要用与当缓存,比如数据库缓存

弱引用

public static void main(String[] args) throws InterruptedException, IOException {
        byte[] bytes = new byte[1024 * 1024 * 30];
        WeakReference soft = new WeakReference(bytes);
        System.out.println(soft.get());
        System.gc();
        System.out.println(soft.get());
        ThreadLocal<byte[]> threadLocal = new ThreadLocal<>();
        threadLocal.set(bytes);
    }

image-1651906948218

  • 只要发生gc 就会被回收。
  • 使用场景 如果这个弱引用的对象 在一个强引用中,只要这个强引用小时,这个弱引用就会被自动回收。
  • 一般是用在容器中。
  • ThreadLocal 就是一个弱引用
  • 原因是如果ThreadLocal 是一个强引用并且他指向了另一个引用,并且那个对象是长驻内存的,这个ThreadLocal 就无法被正常回收。
  • 但是对于ThreadLocal 必须要调用remove 方法
  • 原因是:当 threadlocal 使用完后,将栈中的 threadlocal 变量置为 null,threadlocal 对象下一次 GC 会被回收,那么 Entry 中的与之关联的弱引用 key 就会变成 null,如果此时当前线程还在运行,那么 Entry 中的 key 为 null 的 Value 对象并不会被回收(存在强引用),这就发生了内存泄漏,当然这种内存泄漏分情况,如果当前线程执行完毕会被回收,那么 Value 自然也会被回收,但是如果使用的是线程池呢,线程跑完任务以后放回线程池(线程没有销毁,不会被回收),Value 会一直存在,这就发生了内存泄漏。value还有引用的原因是threadlocalMap 指向了value

虚引用

  • 主要是给写虚拟机的人用的,不想深究。