【问题标题】:Why my WeakHashMap entry doesn't be removed by GC?为什么我的 WeakHashMap 条目不会被 GC 删除?
【发布时间】:2020-04-05 18:18:17
【问题描述】:

我有一个类来管理多个功能的锁对象。我发现 WeakHashMap 应该符合我的要求。这是我的代码:

public static class FeatureLockManager {
        private final Map<Object, WeakKeyLockPair> locks;
        private String domain;

        public FeatureLockManager(String domain) {
            this.domain = domain;
            locks = new WeakHashMap<Object, WeakKeyLockPair>();
        }

        public Lock getLock(Object feature) {
            if (locks.get(feature) == null) {
                synchronized (locks) {
                    locks.computeIfAbsent(feature, l -> new WeakKeyLockPair(feature, new ReentrantLock()));
                }
            }
            return locks.get(feature);
        }

        private static class WeakKeyLockPair implements Lock {
            private final Reference<Object> feature;
            private final Lock lock;

            private WeakKeyLockPair(Object feature, Lock lock) {
                this.feature = new WeakReference<Object>(feature);
                this.lock = lock;
            }
...      }
       }

但是,经过简单的测试,我发现锁对象在GC之后不会被移除。

public static void main(String[] args) throws InterruptedException {
        FeatureLockManager test = new FeatureLockManager("test");
        Lock lock = test.getLock("add user");
        System.out.println(lock.hashCode());
        // do thing
        System.gc();
        Thread.sleep(1000);
        Lock lock1 = test.getLock("add user");
        System.out.println(lock1.hashCode());
        System.out.println(lock1 == lock);
    }

你能告诉我我的实现有什么问题吗? 提前谢谢!

【问题讨论】:

  • System.gc();不强制 GC,它只是建议执行它

标签: java weakhashmap


【解决方案1】:

根据WeakHashMap的java文档

WeakHashMap 中的每个关键对象都间接存储为弱引用的所指对象。因此,只有在 map 内外的弱引用被垃圾收集器清除后,key 才会被自动删除。

您的 FeatureLockManager 类仍然具有对 WeakHashMap 的关键元素(“添加用户”)的强引用。

更多详情,请查看documentation

【讨论】:

  • 问题是"add user"是一个字符串字面量,因此在字符串池中被强行保存。
  • 绝对! @MarkRotteveel
【解决方案2】:

我认为这是因为您在映射中使用字符串作为键,字符串存储在通用字符串池内存中,并且程序的不同部分将使用相同的文字值,因此它不会成为合格对于 GC,我建议使用不同的对象类型或原始包装类型(例如尝试整数表示)或字符串以外的任何其他对象

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2022-11-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-03-11
    • 2017-05-22
    • 2023-03-09
    相关资源
    最近更新 更多