为什么我的 WeakHashMap 条目没有被 GC 删除?

Why my WeakHashMap entry doesn't be removed by GC?

我有一个class来管理几个功能的锁对象。我发现 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);
    }

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

根据 WeakHashMapjava 文档

Each key object in a WeakHashMap is stored indirectly as the referent of a weak reference. Therefore a key will automatically be removed only after the weak references to it, both inside and outside of the map, have been cleared by the garbage collector.

您的 FeatureLockManager class 仍然具有对 WeakHashMap 的关键元素 ("add user") 的强引用。

有关详细信息,请查看 documentation

我认为这是因为您在地图中使用字符串作为键,字符串存储在通用字符串池内存中,程序的不同部分会使用相同的文字值,因此不会有资格使用 GC,我建议使用不同的对象类型或原始包装器类型(例如尝试整数表示)或字符串

以外的任何其他对象