Java中集合的弱引用

时间:2018-12-10 22:02:44

标签: java garbage-collection weak-references

背景故事

在我维护的库中,我们有一个内部地图来跟踪缓存。 库的用户有兴趣访问此映射,但是我们只能通过复制其内容(线程安全性)来提供此访问。 想法是在第一次访问此列表时对其进行缓存,而不会在第二次访问时占用太多内存。 为了说明:

List<Bob> list = cache.asList();
List<Bob> otherList = cache.asList(); // use from cache, if still available

问题是,如果不再需要此列表,我们就不想永远保留它。由于Java使用GC,因此我们认为为此使用WeakReference是合适的,如果未收集它,则允许使用它。

问题

如果我的班级中存储着WeakReference<List<Bob>>,如果其中一个元素变得弱可访问(这意味着列表弱可访问)会发生什么? GC是否有可能决定只收集列表中的元素,还是会查找引用该元素的所有其他弱可达对象并收集它们(在这种情况下为列表)?

问题是,如果GC收集了列表的一个元素,然后我们尝试再次访问该列表(如果可能的话)会发生什么?

说明

我对列表的可访问性不感兴趣,我知道列表位于WeakReference内,并且元素与列表的可访问性无关。我关心一个特定的状态,在该状态下,列表和列表的元素都难以访问,并且GC是否有可能仅收集元素而不是列表本身。在这种特定情况下,GC会做什么?

3 个答案:

答案 0 :(得分:1)

只要List本身不容易被访问,它的元素也不会一样。 (假设列表实现本身不使用弱引用或类似引用)

因此,使用弱引用缓存列表没有问题,因为它将完全被垃圾回收或根本不被垃圾回收。

答案 1 :(得分:0)

在提供的情况下(WeakReference<List<Something>>),您只有以下可能的情况:

public class Test {

    private WeakReference<List<String>> listWeakReference;

    public Test(final WeakReference<List<String>> listWeakReference) {
        this.listWeakReference = listWeakReference;
    }

    public static void main(String[] args) {
        List<String> testList = Arrays.asList("a", "b", "c");

        Test test = new Test(new WeakReference<>(testList));

        // Initial check
        System.out.println(test.listWeakReference.get());

        // Call gc and check
        System.gc();
        System.out.println(test.listWeakReference.get());

        // Remove reference and call gc
        testList = null;
        System.gc();
        System.out.println(test.listWeakReference.get());
    }
}

答案 2 :(得分:0)

首先,SoftReference对于缓存而言更好,即使那样也不是很好。

WeakReference可能立即释放,因此引用变得难以访问。但是,它可能要等到执行后才能执行-也就是说,在广泛的测试期间不会发生,但在生产中会发生。娱乐时间。 NetBeans过去在文件缓存中这样做。当然,其余的代码期望缓存如此之快地被抓取和发布。使用该应用程序一段时间后,它将突然破坏文件I / O并变得不可用。

为了获得最佳性能,您需要明确估计进程正在使用多少内存,并根据需要释放。不容易。

回到问题。收集WeakReference(和SoftReference的内容是一个两阶段的操作。第一阶段只是清除Reference(如果正在使用,则将其排队)。不收集相关的内存。可以通过终结器恢复内存。WeakReference会被永久清除并排队,不会重置。只有当对象完全不可访问时,关联的内存才能作为单独的阶段进行收集。

不要害怕,Java是内存安全(错误除外)。