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,此外,它可以减少程序使用的内存,加速程序的运行。

目录
相关文章
|
11天前
|
缓存 监控 算法
【Java】谈一谈虚引用
【Java】谈一谈虚引用
15 0
|
1月前
|
缓存 Java
【JAVA】强引用、软引用、弱引用、幻象引用有什么区别?
幻象引用:幻象引用是最弱的引用类型,几乎不影响对象的生命周期。它们主要用于在对象被回收前进行某些预处理操作,例如在对象被销毁时执行特定的清理任务。
33 0
|
1月前
|
Java
【JVM】深入理解Java引用类型:强引用、软引用、弱引用和虚引用
【JVM】深入理解Java引用类型:强引用、软引用、弱引用和虚引用
244 0
|
1月前
|
缓存 Java 程序员
Java垃圾回收: 什么是强引用、软引用、弱引用和虚引用?
Java垃圾回收: 什么是强引用、软引用、弱引用和虚引用?
39 2
|
1月前
|
缓存 算法 JavaScript
提高Java程序性能!了解可达性分析算法、强软弱虚引用和三色标记GC的过程,避免不可达对象阻碍程序性能!
提高Java程序性能!了解可达性分析算法、强软弱虚引用和三色标记GC的过程,避免不可达对象阻碍程序性能!
|
8月前
|
SQL 缓存 移动开发
Java内存泄漏知识(软引用、弱引用等)
要学习内存泄漏,我们要知道一些基础知识,如Java引用分类:
|
3天前
|
Java 机器人 程序员
Java中的线程通信:wait、notify与Condition详解
Java中的线程通信:wait、notify与Condition详解
|
3天前
|
存储 安全 Java
Java中的线程安全与同步技术
Java中的线程安全与同步技术
|
2天前
|
监控 Java 调度
Java并发编程:深入理解线程池
【6月更文挑战第26天】在Java并发编程的世界中,线程池是提升应用性能、优化资源管理的关键组件。本文将深入探讨线程池的内部机制,从核心概念到实际应用,揭示如何有效利用线程池来处理并发任务,同时避免常见的陷阱和错误实践。通过实例分析,我们将了解线程池配置的策略和对性能的影响,以及如何监控和维护线程池的健康状况。
7 1
|
1天前
|
存储 缓存 Java
老程序员分享:Java并发编程:线程池的使用
老程序员分享:Java并发编程:线程池的使用