You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为什么WeakHashMap中置为null的lambda表达式键未被GC回收?

问题原因分析

非捕获型Lambda的实例缓存机制

这是该现象的核心原因:

  • Java虚拟机对无外部变量捕获的Lambda表达式有实例复用优化:你代码中的Lambda只用到了函数式接口自身的入参callee1,没有引用方法内的其他局部变量、外部类字段等外部资源,属于典型的非捕获型Lambda。HotSpot虚拟机的实现中,这类Lambda会生成全局单例实例,由其对应生成的匿名类的静态字段强引用持有,这个静态引用的生命周期和类一致,只要类不被卸载,实例就永远存在强引用,不会被垃圾回收。
  • 你代码中key1和key2对应的Lambda实现逻辑完全一致,最终会指向同一个缓存实例(即key1 == key2结果为true),你仅把key1赋值为null,但key2仍然持有该实例的强引用,进一步保证了实例不会被GC清理。

System.gc()不保证强制触发GC

System.gc()只是给虚拟机发送了执行垃圾回收的建议,虚拟机完全可以选择忽略该请求,哪怕没有Lambda缓存的问题,也不能保证调用后立刻执行GC清理弱引用。

验证方法

你可以修改代码生成捕获型Lambda,比如在方法内新增一个局部变量,在Lambda中引用它,此时Lambda会变成捕获型,不会被全局缓存,就可以看到符合预期的回收效果:

@Test
void callBackWithWeakHashMap() {
    Map<Callee.CallBack, String> map = new WeakHashMap<>();
    // 新增局部变量让Lambda捕获,成为捕获型Lambda
    int flag = 1;
    Callee.CallBack key1 = callee1 -> System.out.println("input > " + callee1.getMsg() + flag);
    Callee.CallBack key2 = callee1 -> System.out.println("input > " + callee1.getMsg());

    map.put(key1, "1");
    map.put(key2, "2");

    key1 = null;
    System.gc(); 
    // 此时大概率只会输出key2对应的条目
    map.entrySet().forEach(System.out::println); 
}

内容的提问来源于stack exchange,提问作者dooong dooong

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.25 15:27:02