java引用也有强软弱虚?属实阶级了

132 阅读3分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第1天,点击查看活动详情

前言

java 的引用其实分为 强引用、软引用、弱引用、虚引用。那为什么 java 在设计的时候要分这么多引用类型呢?因为 java 语言是不需要让开发者考虑垃圾回收的,gc 会自己回收,再者便于你控制一个对象的生命周期,由此设计出来了四种引用类型,我们看几个具体介绍

强引用

普通的应用类型,只要有引用指针,GC不会回收 ,例如:Student student = new Student,想要让GC检测并回收此对象,你需要让它引用Null student = null~~ image.png

软引用

软引用我们需要用到jdk自带的SoftReference这个类 SoftReference<T> GC只有在内存不足的时候回收(下面会有测试demo) image.png

弱引用

WeakReference<T>只要触发 GC 对象就会回收 image.png 常见的比如有 ThreadLocal 内部用的就是这个弱引用

虚引用

虚引用是一种特殊的引用方式,专门用于堆外内存的管理 PhantomReference<T> 被回收的对象会放在队列里 image.png

实验

我们用代码来简单测试一下软引用

public static void main(String[] args) throws InterruptedException {
        final int _8M = 1024 * 1024 * 8;
        List<SoftReference<byte[]>> softReferences = new ArrayList<>();
        softReferences.add(new SoftReference<>(new byte[_8M]));
        System.out.println("添加8M"); // 够用
        softReferences.add(new SoftReference<>(new byte[_8M]));
        System.out.println("添加8M"); // 够用
        softReferences.add(new SoftReference<>(new byte[_8M]));
        System.out.println("添加8M"); // 不够用 (会把软引用的对象回收掉)
        // 手动执行GC,让它回收
        System.gc();
        // 这里让主线程等待下,目的是为了让GC立即执行,因为GC这个线程的优先级比较低
        TimeUnit.SECONDS.sleep(1);
        softReferences.forEach(res -> System.out.println(res.get()));
    }

运行之前我们需要配置下程序的环境变量,请看下图,点击运行绿色箭头,编辑主程序

image.png

设置最大运行内存20M,目的是模拟我们的内存空间就20M,这里解释下常用的参数,在我们jvm调优的时候都会用到:

  • Xms 是指设定程序启动时占用内存大小。一般来讲,大点,程序会启动的快一点,但是也可能会导致机器暂时间变慢。
  • Xmx 是指设定程序运行期间最大可占用的内存大小。如果程序运行需要占用更多的内存,超出了这个设置值,就会抛出OutOfMemory异常。
  • Xss 是指设定每个线程的堆栈大小。这个就要依据你的程序,看一个线程大约需要占用多少内存,可能会有多少线程同时运行等。

正常情况下:

添加8M
添加8M
添加8M
[B@312b1dae
[B@7530d0a
[B@27bc2616

内存不够时:GC会主动释放内存,所以前面的两个都为Null了

添加8M
添加8M
添加8M
null
null
[B@312b1dae

应用场景

强引用:普通用法

软引用:缓存

弱引用:防止一些map中内存泄漏的,例如threadlocal中的内存泄漏

虚引用:jvm内部专门管理直接内存的