如何描述 Java 中的 WeakHashMap 它是如何实现在 Key 被 GC 回收后自动清理 Entry 的?
如何描述 Ja va 中的 WeakHashMap 它是如何实现在 Key 被 GC 回收后自动清理 Entry 的?

免费影视、动漫、音乐、游戏、小说资源长期稳定更新! 👉 点此立即查看 👈
先看一个核心机制:WeakHashMap 的 Key 被 GC 回收后,其对应的 Entry 会自动失效。这背后的原理是,它的 Key 被 WeakReference 包装,当没有任何强引用指向这个 Key 时,GC 就可以将其回收。此时,Entry 会进入一种 Key 为 null 的失效状态。后续的 get、put 等操作会触发内部的 expungeStaleEntries() 方法,扫描并移除这些失效的 Entry。
WeakHashMap 的 Key 为什么会被 GC 回收后自动失效?
关键在于,WeakHashMap 内部使用的是 WeakReference 来包装 Key,而非强引用。这意味着,只要这个 Key 对象在程序的其他地方没有被强引用“拴住”,下一次垃圾回收就可能把它带走——而 WeakHashMap 本身并不会阻止这个过程。
这里有个重要的细节:Value 仍然是强引用。如果 Value 反过来又持有了对 Key 的引用(例如,Value 是一个内部类实例,或者显式保存了 Key),那么 Key 实际上就不会被回收,对应的 Entry 自然也就不会消失。
- Key 被回收 ≠ Entry 立刻从 Map 中删除。它只是变成了“已失效”状态,真正的清理动作发生在后续调用
get、put、size等方法时。 - 清理逻辑由
expungeStaleEntries()方法执行,它会扫描整个哈希表,移除那些 key == null 的Entry。 - 由于 Entry 本身继承自
WeakReference,所以当它的get()方法返回 null 时,就明确标志着 Key 已被回收。
WeakHashMap 的 Entry 是怎么关联 Key 和 Value 的?
它的实现并非普通的 HashMap.Entry,而是一个自定义的 Entry 类。这个类同时扮演了两个角色:既是弱引用持有者(继承 WeakReference),又是键值对的容器(持有 value 字段)。
static class Entryextends WeakReference
Key 被存放在父类 WeakReference 的 referent 字段中,因此 GC 可以安全地回收它。而 value 则是一个强引用字段,这就要求使用者必须确保 Value 不会反过来长期持有 Key,否则就会导致内存泄漏的预期失效。
立即学习“Ja va免费学习笔记(深入)”;
- 构造 Entry 时,会将 Key 和一个 ReferenceQueue 一同传入父类构造器:
super(key, queue)。这样,当 GC 回收 Key 后,该 Entry 会被加入到这个队列中。 - 但有趣的是,
WeakHashMap并不主动轮询这个 ReferenceQueue。它依赖的是另一种机制:周期性地扫描 table 数组,寻找 key == null 的 Entry 来进行清理。 - 这就带来一个潜在问题:如果应用程序长期不调用任何
WeakHashMap的公开方法,那些失效的 Entry 可能会一直滞留在哈希表中,占用内存。
WeakHashMap 不适合做缓存的三个硬伤
不少人曾误将其当作轻量级缓存来使用,结果往往遇到一些意料之外的行为。这里必须明确指出它的几个“硬伤”:
size()方法返回的并不是“有效键值对数量”,而是哈希表中所有 Entry 的总数,这包括了那些 Key 已被回收、尚未被清理的失效 Entry。- 它没有任何 LRU(最近最少使用)或 TTL(生存时间)机制。清理完全依赖 GC 触发,时机不可控且延迟可能很高,不适合对实时性有要求的缓存场景。
- 在并发环境下,
get()和put()都不是线程安全的。即使用Collections.synchronizedMap()进行包装,其内部的清理逻辑仍可能在多线程间出现遗漏,导致部分失效 Entry 未被及时移除。
因此,如果真的需要缓存功能,更稳妥的选择是使用 ja va.util.concurrent.ConcurrentHashMap 并配合显式的定时清理策略,或者直接采用专业的缓存库,如 Caffeine。
什么时候该用 WeakHashMap?
那么,它的用武之地在哪里呢?一个典型的场景是“附着式元数据”:当你有一组外部对象(例如 GUI 组件、Bean 实例),需要为它们临时附加一些信息,同时又不想影响这些对象本身的垃圾回收。
- 例如,记录某个
JButton当前是否处于悬停状态,可以使用WeakHashMap来存储。当按钮被销毁后,对应的 Entry 会自动失效。 - 再比如,在某些框架中,需要给任意对象打上标记(
WeakHashMap),使用WeakHashMap可以避免框架持有的引用阻止用户对象的正常回收。 - 使用时的关键约束再次强调:Value 绝对不能持有对 Key 的强引用,否则整个弱引用机制将形同虚设。
最后需要牢记的是,WeakHashMap 的“自动清理”本质上是一种被动的、延迟的清理。它依赖于方法调用来触发,而非实时进行。这一点最容易被忽略,也往往是许多线上问题的根源所在。
游乐网为非赢利性网站,所展示的游戏/软件/文章内容均来自于互联网或第三方用户上传分享,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系youleyoucom@outlook.com。
同类文章
使用Python合并与拆分Excel单元格的实用方法
使用Python合并与拆分Excel单元格的实用方法 处理Excel表格时,合并单元格是个绕不开的操作。无论是为了制作清晰美观的表头,还是为了突出显示某些关键信息,这个功能都相当实用。不过,当需要批量处理或者将流程自动化时,手动在Excel里点点划划就有点力不从心了。今天,我们就来聊聊如何用Pyth
SpringBoot OpenFeign整合okHttpClient实践
前言 在SpringCloud微服务架构中,服务间的数据传输,OpenFeign无疑是那个既简单又好用的选择。不过,它默认使用的客户端是JDK自带的HttpURLConnection,这里有个小细节值得注意:这个客户端本身并不具备连接池功能。 这意味着什么?简单来说,每一次发起远程调用,系统都会尝试
修改JAR文件并重新打包的两种方式
本文介绍两种修改 JAR 包内文件(如配置文件或 Class 文件)后重新打包的方式:Ja va 命令方式 与 Ant 脚本方式。 核心警告 对于 Spring Boot 的可执行 JAR 包,重新打包时严禁使用压缩(必须使用存储模式),否则会导致 ClassNotFoundException 或启
C++中INI配置文件读取技术详解
一、INI文件格式概述 在众多配置文件格式中,INI(Initialization)格式堪称经典。它以纯文本形式存储,结构清晰直观,既便于开发者手动编辑与维护,也易于程序进行自动化解析与读取。这种简单高效的特点,使其在软件配置、游戏设置、系统参数管理等场景中,至今仍被广泛应用。 1 1 基本结构 一
idea如何保存当前已修改的文件|恢复到未修改状态
1、打开git,如下步骤1 先来看第一张图,这是整个操作的起点。 在步骤2的区域,你会看到所有被修改过的文件都列在这里,一目了然。 而步骤3指向的代码区域,正是我们修改后还在报错的部分,问题就出在这儿。 这里有个关键细节:注意看圈4标识的地方,你所有修改过的代码行,IDE都会用淡绿色的背景高亮显示,
- 日榜
- 周榜
- 月榜
1
2
3
4
5
6
7
8
9
10
相关攻略
2015-03-10 11:25
2015-03-10 11:05
2021-08-04 13:30
2015-03-10 11:22
2015-03-10 12:39
2022-05-16 18:57
2025-05-23 13:43
2025-05-23 14:01
热门教程
- 游戏攻略
- 安卓教程
- 苹果教程
- 电脑教程
热门话题

