首页 游戏 软件 资讯 排行榜 专题
首页
编程语言
如何描述 Java 中的 WeakHashMap 它是如何实现在 Key 被 GC 回收后自动清理 Entry 的?

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

热心网友
37
转载
2026-04-30

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

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

免费影视、动漫、音乐、游戏、小说资源长期稳定更新! 👉 点此立即查看 👈

先看一个核心机制:WeakHashMap 的 Key 被 GC 回收后,其对应的 Entry 会自动失效。这背后的原理是,它的 Key 被 WeakReference 包装,当没有任何强引用指向这个 Key 时,GC 就可以将其回收。此时,Entry 会进入一种 Key 为 null 的失效状态。后续的 getput 等操作会触发内部的 expungeStaleEntries() 方法,扫描并移除这些失效的 Entry。

WeakHashMap 的 Key 为什么会被 GC 回收后自动失效?

关键在于,WeakHashMap 内部使用的是 WeakReference 来包装 Key,而非强引用。这意味着,只要这个 Key 对象在程序的其他地方没有被强引用“拴住”,下一次垃圾回收就可能把它带走——而 WeakHashMap 本身并不会阻止这个过程。

这里有个重要的细节:Value 仍然是强引用。如果 Value 反过来又持有了对 Key 的引用(例如,Value 是一个内部类实例,或者显式保存了 Key),那么 Key 实际上就不会被回收,对应的 Entry 自然也就不会消失。

  • Key 被回收 ≠ Entry 立刻从 Map 中删除。它只是变成了“已失效”状态,真正的清理动作发生在后续调用 getputsize 等方法时。
  • 清理逻辑由 expungeStaleEntries() 方法执行,它会扫描整个哈希表,移除那些 key == null 的 Entry
  • 由于 Entry 本身继承自 WeakReference,所以当它的 get() 方法返回 null 时,就明确标志着 Key 已被回收。

    WeakHashMap 的 Entry 是怎么关联 Key 和 Value 的?

    它的实现并非普通的 HashMap.Entry,而是一个自定义的 Entry 类。这个类同时扮演了两个角色:既是弱引用持有者(继承 WeakReference),又是键值对的容器(持有 value 字段)。

    static class Entry extends WeakReference implements Map.Entry {
        final int hash;
        V value;
        Entry next;
        // ...
    }
    

    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 的“自动清理”本质上是一种被动的、延迟的清理。它依赖于方法调用来触发,而非实时进行。这一点最容易被忽略,也往往是许多线上问题的根源所在。

    来源:https://www.php.cn/faq/2393288.html
    免责声明: 游乐网为非赢利性网站,所展示的游戏/软件/文章内容均来自于互联网或第三方用户上传分享,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系youleyoucom@outlook.com。

    相关攻略

    怎么通过分析 **Java 内存模型(JMM)**的内存屏障语义理解 volatile 的禁止重排原理
    编程语言
    怎么通过分析 **Java 内存模型(JMM)**的内存屏障语义理解 volatile 的禁止重排原理

    怎么通过分析 Ja va 内存模型(JMM)的内存屏障语义理解 volatile 的禁止重排原理 先明确一个核心机制:volatile变量的写操作会触发StoreStore和StoreLoad屏障。前者确保了它之前所有的普通写操作,都不会被重排到它之后;而后者则阻止了它之后的任意读操作提前执行。理解

    热心网友
    04.30
    Java 中 String.getBytes() 返回不同结果的原因解析
    编程语言
    Java 中 String.getBytes() 返回不同结果的原因解析

    Ja va 中 String getBytes() 返回不同结果的原因解析 String getBytes() 每次调用返回的是新创建的 byte[] 实例,其 toString() 默认输出为内存地址标识(如 [B@1b6d3586),因此看似“不同”;但数组内容完全一致,差异仅源于对象引用不同。

    热心网友
    04.29
    如何在 Java 中利用 WeakReference 防止由于缓存对象导致的内存溢出
    编程语言
    如何在 Java 中利用 WeakReference 防止由于缓存对象导致的内存溢出

    如何在 Ja va 中利用 WeakReference 防止由于缓存对象导致的内存溢出 先说一个核心结论:WeakReference 不能直接用于常规缓存,它只适合“可丢弃”的临时引用场景。 很多开发者误以为它能自动管理内存,结果掉进了坑里。 为什么 WeakReference 不适合做通用缓存 道

    热心网友
    04.29
    如何在 Java 中利用 Collectors.collectingAndThen() 在收集完成后将结果转为不可变
    编程语言
    如何在 Java 中利用 Collectors.collectingAndThen() 在收集完成后将结果转为不可变

    如何在 Ja va 中利用 Collectors collectingAndThen() 在收集完成后将结果转为不可变 collectingAndThen() 的核心作用不是“变不可变”,而是“后处理” 首先得澄清一个常见的误解:Collectors collectingAndThen() 本身并不

    热心网友
    04.29
    Java SSL调试日志中如何唯一标识多TLS连接?
    编程语言
    Java SSL调试日志中如何唯一标识多TLS连接?

    Ja va SSL调试日志中如何唯一标识多TLS连接? Ja va SSL调试日志本身不直接标记TLS连接ID,但可通过线程ID(第3字段)与线程名(第4字段)组合,在单次握手生命周期内准确定位归属;需注意线程复用场景下该组合仅反映处理线程而非连接本身。 排查多TLS连接问题时,面对满屏的SSL调试

    热心网友
    04.29

    最新APP

    宝宝过生日
    宝宝过生日
    应用辅助 04-07
    台球世界
    台球世界
    体育竞技 04-07
    解绳子
    解绳子
    休闲益智 04-07
    骑兵冲突
    骑兵冲突
    棋牌策略 04-07
    三国真龙传
    三国真龙传
    角色扮演 04-07

    热门推荐

    Origin Code发布VORTEX系列LCD水冷冷头
    娱乐
    Origin Code发布VORTEX系列LCD水冷冷头

    Origin Code发布VORTEX系列专用分体式水冷冷头模块 2026年4月7日,知名内存模组品牌Origin Code正式发布了专为VORTEX系列内存打造的分体式水冷冷头模块,官方售价为899元。这款产品的推出,为追求极致散热性能、低温和系统视觉一体化的高端DIY玩家及超频爱好者,提供了一个

    热心网友
    04.30
    荣耀WIN游戏本4月23日发布,首发RTX 5060/5
    娱乐
    荣耀WIN游戏本4月23日发布,首发RTX 5060/5

    荣耀WIN游戏本定档4月23日:性能释放突破250瓦,电竞体验全面升级 2026年4月7日,荣耀正式揭晓了全新WIN游戏本的发布日期:4月23日。这款备受瞩目的产品其实早已不是秘密,早在去年12月,荣耀PC产品负责人就已经在公开渠道透露了新品的进展,并确认了一个关键身份——它将成为《三角洲行动》职业

    热心网友
    04.30
    DRAM供应紧张致苹果Mac Mini/Mac Stud
    娱乐
    DRAM供应紧张致苹果Mac Mini/Mac Stud

    内存供应趋紧,苹果部分Mac交付周期显著延长 进入2026年第二季度,全球半导体产能的重新分配仍在持续。一个不容忽视的趋势是,人工智能应用的爆发式增长,正持续推高对高性能内存芯片的需求,导致DRAM市场供应整体趋紧。自去年下半年开始的这轮价格上涨,让终端设备制造商普遍感受到了成本压力,即便是供应链管

    热心网友
    04.30
    荣威全新i6上市:7.49万起售,搭载8155芯片与国潮
    娱乐
    荣威全新i6上市:7.49万起售,搭载8155芯片与国潮

    荣威全新i6上市:7 49万起售,搭载8155芯片与国潮 2026年4月30日,荣威品牌旗下的全新一代紧凑型轿车i6正式推向市场。新车一口气带来了三款配置,分别命名为长久版、豪久版与臻久版,官方给出的指导价区间定在7 49万元到8 49万元。不过,眼下正值上市初期,官方还推出了限时抢订政策,实际支付

    热心网友
    04.30
    暗黑4憎恨之王上线:术士召唤流凭机制革新成当前最强职业
    娱乐
    暗黑4憎恨之王上线:术士召唤流凭机制革新成当前最强职业

    暗黑破坏神4:憎恨之王上线后,术士职业迅速跻身当前版本最具统治力的职业行列 其核心能力涵盖恶魔召唤、地狱火攻击与神秘印记体系,其中一种以“召唤即献祭”为运转逻辑的召唤流派正展现出显著优势。 这次资料片带来的技能系统重构,可以说是一次彻底的革新:所有被动技能被移除,每个主动技能都扩展成了拥有多节点分支

    热心网友
    04.30