Java 中的强引用、弱引用、软引用和虚引用

简介: 引用方式内存不足时垃圾回收机制启动时其余情况强引用否否否软引用是否否弱引用是是否虚引用可能可能可能在一般的程序中,弱引用和虚引用很少会被用到,强引用天天都在用就不必我说了,在有些情况下(如资源文件很大,但并不是全部要在同一时刻使用)我们会使用软引用来代替原来的强引用,一是可以避免某些情况下产生的 OOM,此外,它可以减少程序使用的内存,加速程序的运行。

一、继承结构

1.1 四大引用的继承关系

在 Java 中一共有四种引用类型,分别是强引用、弱引用、软引用和虚引用,其中,我们常用的是强引用,而其他三种引用都需要引入特定的 java.lang.ref 才能使用,他们的继承结构如下:

引用继承结构图image.gif编辑

一般只有强引用是直接使用的,而其他的三种引用都需要配合引用队列(ReferenceQueue)来使用会更好。

Java 中变量的类型有两大类,值类型和引用类型,这里的引用类型就是指可以引用的对象。在对引用类型进行操作时,我们实际只是得到了它的内存地址,通过内存地址来访问这个对象,并对其进行相关的操作,这和 C++ 的指针极为相似,但不完全相同。C++ 有基础数据类型的指针,而 Java 没有基础数据类型的引用,取而代之的是值类型。

1.2 引用和指针的关系

这里拓展和延伸一下,具体解释 C++ 中的指针、引用和 Java 的引用之间的区别和联系。

C++ 的指针

C++ 中的指针指向对象的内存地址,在参数传递时,以指针传递时只会将对象的内存地址传过去,在函数或方法内部再对地址进行访问以达到传参的目的。

Java 的引用

Java 中的引用和 C++ 中的指针类似,但是也不完全相同。Java 中的引用没有基础类型的引用,只能是引用类型,因此相比于 C++,没有 int 类型变量的地址一说,Java 只能得到引用类型的地址,无法得到基本数据类型的内存地址。

C++ 的引用

C++ 中也是有引用的,不过 C++ 的引用和指针以及 Java 的引用不同,它是变量或者对象的别名,和拷贝不一样,它是直接对原本的数据进行操作的。

二、四大引用方式

2.1 强引用(Reference)

使用强引用不需要引入任何包,Java 的引用方式默认就是强引用。

我们一般使用的引用都是强引用,当内存不足时,JVM 开始回收垃圾,但对于强引用的对象,JVM 不会对其进行回收,就算出现了 OOM(OutOfMemory),JVM 也不会对其进行回收,也就是说,强引用的对象是不会被 JVM 给回收的。这可以防止一些资源在程序运行的时候被回收了,当然,有利也有弊,当一些资源过大时,它们会占用大量的内存,甚至出现了 OOM 时,JVM 依然不会对其回收,这可能导致程序出现问题。在某些情况下,这会造成程序的内存泄露。

2.2 软引用(SoftReference)

使用软引用需要引入 java.lang.ref.SoftReference。

软引用不像强引用那么绝对,当内存不足时,JVM 就会尝试回收垃圾,而软引用的对象在这个时候就会被回收。不过,若没有达到内存不足的情况,JVM 不会回收软引用的对象。软引用的这个特性非常好,可以说它就是 Java 自动管理内存的标配,为什么这么说呢?我们知道,Java 是可以自动管理内存的,但在程序的运行过程中,JVM 是无法自动判断某些内存空间的,而这部分空间如果都是强引用对象且占用了很大的内存,甚至导致出现了 OOM,那么程序就出问题。这个时候,程序员就应该将其设定为软引用,告诉 JVM,这个对象在内存不足的时候是可以释放的。图片资源的缓存,网页资源的缓存中就大量使用了软引用。

2.3 弱引用(WeakReference)

使用弱引用需要引入 java.lang.ref.WeakReference。

弱引用,是一种比软引用还要“弱”的引用方式。当 Java 的垃圾回收机制开始运行时,弱引用的对象就会立刻被回收,无论内存是否充足。弱引用一般使用不多。

2.4 虚引用(PhantomReference)

使用虚引用需要引入 java.lang.ref.PhantomReference。

虚引用,顾名思义,其引用是虚的,并非真实的引用,因此可以认为这个对象没有任何引用,这个对象也无法通过虚引用被访问。虚引用对象在任何时候都可能被回收。虚引用可以理解为给这个对象打了个标记,程序员可以从中知道,这个对象要被回收或者已经被回收,虚引用的存在只是象征着这个对象曾经存在过。

三、总结

以上四种引用方式可以总结为下表:

引用方式 内存不足时 垃圾回收机制启动时 其余情况
强引用
软引用
弱引用
虚引用 可能 可能 可能

在一般的程序中,弱引用和虚引用很少会被用到,强引用天天都在用就不必我说了,在有些情况下(如资源文件很大,但并不是全部要在同一时刻使用)我们会使用软引用来代替原来的强引用,一是可以避免某些情况下产生的 OOM,此外,它可以减少程序使用的内存,加速程序的运行。

目录
相关文章
|
5月前
|
缓存 Java 程序员
Java面试题:解释强引用、软引用、弱引用和虚引用在Java中是如何工作的?
Java面试题:解释强引用、软引用、弱引用和虚引用在Java中是如何工作的?
40 1
|
6月前
|
缓存 Java 数据库连接
java面试题目 强引用、软引用、弱引用、幻象引用有什么区别?具体使用场景是什么?
【6月更文挑战第28天】在 Java 中,理解和正确使用各种引用类型(强引用、软引用、弱引用、幻象引用)对有效的内存管理和垃圾回收至关重要。下面我们详细解读这些引用类型的区别及其具体使用场景。
95 3
|
5月前
|
Java 运维
开发与运维引用问题之软引用又在Java特点如何解决
开发与运维引用问题之软引用又在Java特点如何解决
49 0
|
6月前
|
缓存 监控 算法
【Java】谈一谈虚引用
【Java】谈一谈虚引用
92 0
|
7月前
|
缓存 Java
【JAVA】强引用、软引用、弱引用、幻象引用有什么区别?
幻象引用:幻象引用是最弱的引用类型,几乎不影响对象的生命周期。它们主要用于在对象被回收前进行某些预处理操作,例如在对象被销毁时执行特定的清理任务。
64 0
|
7月前
|
Java
【JVM】深入理解Java引用类型:强引用、软引用、弱引用和虚引用
【JVM】深入理解Java引用类型:强引用、软引用、弱引用和虚引用
523 0
|
9天前
|
安全 Java API
java如何请求接口然后终止某个线程
通过本文的介绍,您应该能够理解如何在Java中请求接口并根据返回结果终止某个线程。合理使用标志位或 `interrupt`方法可以确保线程的安全终止,而处理好网络请求中的各种异常情况,可以提高程序的稳定性和可靠性。
38 6
|
23天前
|
设计模式 Java 开发者
Java多线程编程的陷阱与解决方案####
本文深入探讨了Java多线程编程中常见的问题及其解决策略。通过分析竞态条件、死锁、活锁等典型场景,并结合代码示例和实用技巧,帮助开发者有效避免这些陷阱,提升并发程序的稳定性和性能。 ####
|
21天前
|
存储 监控 小程序
Java中的线程池优化实践####
本文深入探讨了Java中线程池的工作原理,分析了常见的线程池类型及其适用场景,并通过实际案例展示了如何根据应用需求进行线程池的优化配置。文章首先介绍了线程池的基本概念和核心参数,随后详细阐述了几种常见的线程池实现(如FixedThreadPool、CachedThreadPool、ScheduledThreadPool等)的特点及使用场景。接着,通过一个电商系统订单处理的实际案例,分析了线程池参数设置不当导致的性能问题,并提出了相应的优化策略。最终,总结了线程池优化的最佳实践,旨在帮助开发者更好地利用Java线程池提升应用性能和稳定性。 ####
|
23天前
|
缓存 Java 开发者
Java多线程编程的陷阱与最佳实践####
本文深入探讨了Java多线程编程中常见的陷阱,如竞态条件、死锁和内存一致性错误,并提供了实用的避免策略。通过分析典型错误案例,本文旨在帮助开发者更好地理解和掌握多线程环境下的编程技巧,从而提升并发程序的稳定性和性能。 ####