引言

在JDK1.2之前Java并没有提供软引用、弱引用和虚引用这些高级的引用类型。而是提供了一种基本的引用类型,称为Reference。并且当时Java中的对象只有两种状态:被引用和未被引用。当一个对象被引用时,它将一直存在于内存中,直到它不再被任何引用指向时,才会被垃圾回收器回收。而被引用也就是强引用。

而在JDK1.2之后对引用的概念进行了扩充,分为了强引用(StrongReference)、软引用(SoftReference)、弱引用(WeakReference)和虚引用(PhantomReference),这4种引用的强度依次减弱。他们的关系如下如:

强引用

强引用是Java中最常见的引用类型。当你创建一个对象并将其赋值给一个变量时,这个变量会持有该对象的强引用。

Order order = new Order(); // 只要order还指向Order对象,那么Order对象就不会被回收
order = null; // 强引用都被设置为 null 时,不可达,则Order对象被回收

只要存在强引用指向对象,垃圾回收器将永远不会回收该对象,即使内存不足也不会回收。这可能导致内存溢出,因为即使内存不足,JVM也不会回收强引用对象。当强引用都被设置为null时,对象变成不可达状态,垃圾回收器会在适当的时候将其回收。

比如以下示例,我们创建一个2M的数组,但是我们设置JVM参数:-Xms2M -Xmx3M,将JVM的初始内存设为2M,最大可用内存为3M。

public static void main(String[] args) {
//定义一个2M的数组
byte[] objects = new byte[1024 * 1024 * 2];
}

此时我们执行方法后,发现报错:



对于强引用,即使内存不够使用,直接报错OOM,强引用也不会被回收。

对于强引用,就好比生活中,当我们拥有家里的钥匙时,我们可以随时进入你的家,即使我们不需要进入,也能确保我们可以进入。钥匙是我们进入家的强引用。只有当我们不再拥有钥匙时,我们才无法进入家,类似于当没有强引用指向一个对象时,该对象才能被垃圾回收。

软引用

在JDK1.2之后,用java.lang.ref.SoftReference类来表示软引用。软引用允许对象在内存不足时被垃圾回收器回收。如果一个对象只有软引用指向它,当系统内存不足时,垃圾回收器会尝试回收这些对象来释放内存,如果回收了软引用对象之后仍然没有足够的内存,才会抛出内存溢出异常。软引用适用于需要缓存大量对象,但又希望在内存不足时释放部分对象以避免内存溢出的情况,用于实现缓存时,当内存紧张时,可以释放部分缓存对象以保证系统的稳定性。

以下示例我们设置JVM参数为:-Xms3M -Xmx5M,然后连续创建了10个大小为1M的字节数组,并赋值给了软引用,然后循环遍历将这些对象打印出来。

private static final List<Object> list = Lists.newArrayList();  

public static void main(String[] args) {
IntStream.range(0, 10).forEach(i -> {
byte[] buff = new byte[1024 * 1024];
SoftReference<byte[]> sr = new SoftReference<>(buff);
list.add(sr);
}); System.gc(); // 主动通知垃圾回收 list.forEach(l -> {
Object obj = ((SoftReference<?>) l).get();
System.out.println("Object: " + obj);
});
}

然后我们执行代码之后:



对于打印结果中,只有最后一个对象保留了下来,其他的obj全都被置空回收了。即说明了在内存不足的情况下,软引用将会被自动回收。

对于弱引用,就像我们医药箱里的备用药,当我们需要药品时,我们会先看看医药箱里是否有备用药。如果医药箱里有足够的药品(内存足够),我们就可以使用备用药;但如果医药箱里的备用药不够了(内存不足),我们可能会去药店购买。在内存不足时,垃圾回收器可能会回收软引用对象,类似于我们在医药箱里的备用药被用完时去药店购买。

弱引用

JDK1.2之后,用java.lang.ref.WeakReference来表示弱引用。弱引用与软引用类似,但强度更弱。即使内存足够,只要没有强引用指向一个对象,垃圾回收器就可以随时回收该对象。弱引用适用于需要临时引用对象的场景,如临时缓存或临时存储对象。也可以用于解决对象之间的循环引用问题,避免内存泄漏。

对于上述示例中,我们将数组赋值给弱引用

private static final List<Object> list = Lists.newArrayList();  

public static void main(String[] args) {
IntStream.range(0, 10).forEach(i -> {
byte[] buff = new byte[1024 * 1024];
WeakReference<byte[]> sr = new WeakReference<>(buff);
list.add(sr);
}); System.gc(); // 主动通知垃圾回收 list.forEach(l -> {
Object obj = ((WeakReference<?>) l).get();
System.out.println("Object: " + obj);
});
}

执行结果发现所有的对象都是null,即都被回收了。

对于弱引用,就像我们正在旅行,使用一张一次性地图。我们只在需要导航时使用地图,一旦旅行结束,我们就不再需要地图了。这时我们可以选择扔掉地图,类似于弱引用,在垃圾回收器运行时,无论内存是否充足,对象都可能被回收。

虚引用

在 JDK1.2之后,用java.lang.ref.PhantomReference类来表示虚引用。虚引用是最弱的引用类型,它几乎对对象没有任何影响,不能通过虚引用获取对象,也不能通过它来阻止对象被垃圾回收。从源码中可以看出它只有一个构造函数和一个 get() 方法,而且它的 get() 方法仅仅是返回一个null,也就是说将永远无法通过虚引用来获取对象,虚引用必须要和 ReferenceQueue 引用队列一起使用。

虚引用可以用于在对象被回收时进行后续操作,如对象资源释放或日志记录,常用于跟踪对象被垃圾回收的状态,执行一些清理工作。

而对于弱引用,就像我们去商店,商店入口处的门闩并不直接影响你进入房屋,但它会在有人进入或离开时发出声音,提醒你有人进店(欢迎光临)或者离开(欢迎再来)。类似地,虚引用并不直接影响对象的生命周期,但它可以在对象被回收时发出通知,让你有机会进行一些后续操作,比如资源释放或者记录日志。

引用队列

引用队列(ReferenceQueue)是Java中的一个特殊队列,用于配合软引用、弱引用和虚引用,实现更灵活的对象引用和回收管理。

引用队列的主要作用是跟踪对象的垃圾回收过程。当一个软引用、弱引用或虚引用指向的对象被垃圾回收器回收时,如果它们与一个引用队列关联,那么这些引用就会被自动加入到引用队列中。通过监视引用队列中的对象,我们可以了解到对象的回收状态,从而执行一些额外的操作,比如资源释放或日志记录等。

总结

Java中的四种引用类型各具特点,可根据程序需求选择合适的引用类型。强引用保证对象不被意外回收,软引用和弱引用用于实现缓存或解决内存敏感问题,而虚引用则用于对象回收后的通知和清理操作。合理使用引用类型可以更好地管理内存和避免内存泄漏问题。

本文已收录于我的个人博客:码农Academy的博客,专注分享Java技术干货,包括Java基础、Spring Boot、Spring Cloud、Mysql、Redis、Elasticsearch、中间件、架构设计、面试题、程序员攻略等

美团一面:说一说Java中的四种引用类型?的更多相关文章

  1. Java中的四种引用类型比较

    1.引用的概念 引用这个概念是与JAVA虚拟机的垃圾回收有关的,不同的引用类型对应不同的垃圾回收策略或时机. 垃圾收集可能是大家感到难于理解的较难的概念之一,因为它并不能总是毫无遗漏地解决Java运行 ...

  2. Java中的四种引用类型,强引用,软引用,弱引用,虚引用

    对于Java中的垃圾回收机制来说,对象是否被回收的标准在于该对象是否被引用.因此,引用也是JVM进行内存管理的一个重要概念. Java中对象的引用一般有以下4种类型: 1强引用  2软引用  3弱引用 ...

  3. Java 中的四种引用类型(转)

    目录 背景 简介          1. 强引用 StrongReference          2. 弱引用 WeakReference          3. 软引用 SoftReference ...

  4. java中的四种引用类型

    为什么需要引用: Java的内存回收不需要程序员负责,JVM会在必要时启动Java GC完成垃圾回收. Java以便我们控制对象的生存周期,提供给了我们四种引用方式,引用强度从强到弱分别为:强引用.软 ...

  5. JAVA基础学习之throws和throw的区别、Java中的四种权限、多线程的使用等(2)

    1.throws和throw的区别 throws使用在函数外,是编译时的异常,throw使用在函数内,是运行时的异常 使用方法 public int method(int[] arr) throws ...

  6. JAVA中的四种引用以及ReferenceQueue和WeakHashMap的使用示例

    简介: 本文主要介绍JAVA中的四种引用: StrongReference(强引用).SoftReferenc(软引用).WeakReferenc(弱引用).PhantomReference(虚引用) ...

  7. Java中的四种引用

    引用定义 实际上,Java中存在四种引用,它们由强到弱依次是:强引用.软引用.弱引用.虚引用.下面我们简单介绍下这四种引用: 强引用(Strong Reference):通常我们通过new来创建一个新 ...

  8. JAVA中的四种JSON解析方式详解

    JAVA中的四种JSON解析方式详解 我们在日常开发中少不了和JSON数据打交道,那么我们来看看JAVA中常用的JSON解析方式. 1.JSON官方 脱离框架使用 2.GSON 3.FastJSON ...

  9. Java入门系列 Java 中的四种引用

    Why java内存管理分为内存分配和内存回收,都不需要程序员负责,垃圾回收的机制主要是看对象是否有引用指向该对象. java对象的引用包括强引用,软引用,弱引用,虚引用 Java中提供这四种引用类型 ...

  10. java中的四种引用方式(强引用,软引用,弱引用,虚引用)

    java内存管理主要有内存分配和内存回收,都不需要程序员负责,垃圾回收的机制主要是看对象是否有引用指向该对象. java中对象的引用主要有四种:强引用,软引用,弱引用,虚引用. Java中提供这四种引 ...

随机推荐

  1. Power BI 12 DAY

    电商平台流量分析 案例练习 参数建模 建模-->新建参数 新建度量值使用SWITCH函数将需要的指标数据化 15.关键指标 = switch([指标选择 值],1,[1.访客数合计],2,[2. ...

  2. Js实用小技巧

    Js实用小技巧 这是一份Js实用小技巧,也可以是一份Js挨打小技巧,下面的一系列操作虽然能够在一定程度上使代码更加简洁,但是在缺少注释的情况下会降低可读性,所以需要谨慎使用这些黑魔法. 位元算 取整 ...

  3. Shiro实战2-Springboot集成Shiro实战

    说明 最近打算打造一个简易的权限管理系统,打算用shiro做认证和授权.本篇作为springboot集成shiro的入门实战案例记录下来,希望也可以帮到大家,代码整理自网络. 技术栈 springbo ...

  4. spring boot整合spring cloud

    本项目还是通过卖票和买票模块来介绍spring cloud. 1.新建服务注册模块:eureka-server 1.1 配置pom <?xml version="1.0" e ...

  5. Java并发编程实例--12.使用线程工厂创建线程

    工厂模式是面向对象编程世界中最有用的设计模式. 它是一个创新型的模式,目标是开发一个对象,这个对象的任务是去创建其他类对象. 这样一来,如果我们想创建某些类的对象就不需要使用new关键字.好处有以下几 ...

  6. 【Android逆向】反调试绕过(nop 绕过)

    1. 这是看雪上的一个题目,要求显示出 it is success https://www.kanxue.com/work-task_read-800648.htm 第三题 2. apk 安装到手机, ...

  7. [Android 逆向]Xposed 破解 切水果大战原版.apk

    代码 public class Main implements IXposedHookLoadPackage { boolean flag = false; @Override public void ...

  8. ROS2 humble交叉编译环境配置

    目录 配置 toolchain文件: 库文件 交叉编译指令: 问题点: 1.find_package找不到自定义依赖包的问题 2.libarmadillo.so.10: undefined refer ...

  9. 如何处理Long类型精度丢失问题?

    一.现象与分析: 1.1. 现象 前后端交互,当后端传一些值给前端的时候,如果是long类型,有可能会出现数字太大而前端接收不了(java中的long大于js的number)而导致数据不一致,精度会丢 ...

  10. Navicat安装包和激活工具

    链接:https://pan.baidu.com/s/11YuOKdgGakt3E8CL80aA2g 提取码:h4f3