Android:GC 不尊重 SoftReferences?

标签 android garbage-collection weak-references soft-references

看起来 Dalvik 的垃圾收集器不尊重 SoftReferences 并尽快删除它们,就像 WeakReferences 一样。我还不是 100% 确定,但尽管事实上仍有大约 3MB 的可用内存,但在我在 LogCat 中看到“GC freed bla-bla-bla bytes”后,我的 SoftReferences 被清除了。

此外,我还看到了 Mark Murphy 的评论 here :

Except that it doesn't work on Android, at least in the 1.5 timeframe. I have no idea if the GC SoftReference bugs have been fixed. SoftReferences get GC'd too soon with this bug.

这是真的吗?是否不尊重 SoftReferences?

如何解决这个问题?

最佳答案

在没有收到答复后,我决定自己研究。我做了一个简单的测试来针对 SoftReferences 执行 GC。

public class TestSoftReference extends TestCase {

    public void testSoftRefsAgainstGc_1() {        testGcWithSoftRefs(1);    }

    public void testSoftRefsAgainstGc_2() {        testGcWithSoftRefs(2);    }

    public void testSoftRefsAgainstGc_3() {        testGcWithSoftRefs(3);    }

    public void testSoftRefsAgainstGc_4() {        testGcWithSoftRefs(4);    }

    public void testSoftRefsAgainstGc_5() {        testGcWithSoftRefs(5);    }

    public void testSoftRefsAgainstGc_6() {        testGcWithSoftRefs(6);    }

    public void testSoftRefsAgainstGc_7() {        testGcWithSoftRefs(7);    }


    private static final int SR_COUNT = 1000;

    private void testGcWithSoftRefs(final int gc_count) {
        /* "Integer(i)" is a referrent. It is important to have it referenced
         * only from the SoftReference and from nothing else. */
        final ArrayList<SoftReference<Integer>> list = new ArrayList<SoftReference<Integer>>(SR_COUNT);
        for (int i = 0; i < SR_COUNT; ++i) {
            list.add(new SoftReference<Integer>(new Integer(i)));
        }

        /* Test */
        for (int i = 0; i < gc_count; ++i) {
            System.gc();

            try {
                Thread.sleep(200);
            } catch (final InterruptedException e) {
            }
        }

        /* Check */
        int dead = 0;
        for (final SoftReference<Integer> ref : list) {
            if (ref.get() == null) {
                ++dead;
            }
        }
        assertEquals(0, dead);
    }
}

我的想法是,我每次运行相同的代码都会增加对 SoftReferences 的压力(通过运行更多的 GC 遍数)。

结果非常有趣:除了一次以外,所有运行都顺利通过!

On Android 1.5 device:
testSoftRefsAgainstGc_1()  FAILED!  AssertionFailedError: expected:0 but was:499
testSoftRefsAgainstGc_2()  passed
testSoftRefsAgainstGc_3()  passed
testSoftRefsAgainstGc_4()  passed
testSoftRefsAgainstGc_5()  passed
testSoftRefsAgainstGc_6()  passed
testSoftRefsAgainstGc_7()  passed


On Android 1.6 device:
testSoftRefsAgainstGc_1()  passed
testSoftRefsAgainstGc_2()  FAILED!  AssertionFailedError: expected:0 but was:499
testSoftRefsAgainstGc_3()  passed
testSoftRefsAgainstGc_4()  passed
testSoftRefsAgainstGc_5()  passed
testSoftRefsAgainstGc_6()  passed
testSoftRefsAgainstGc_7()  passed

On Android 2.2 device:
All pass.

这些测试结果是稳定的。我试过很多次,每次都是一样的。所以我相信这确实是垃圾收集器中的一个错误。

结论

因此,我们从中学到了什么......在您的代码中使用 SoftReferences 对于 Android 1.5-1.6 设备毫无意义。对于这些设备,您将不会获得您期望的行为。但是,我没有尝试 2.1。

关于Android:GC 不尊重 SoftReferences?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4014033/

相关文章:

html页面的Android KitKat webview宽度

android - 哪种 Activity 生命周期方法最适合注册/取消注册到事件总线?

c# - 如何在 .NET Core 中启用服务器 GC?

android - 什么时候(如果有的话)我应该使用 Bitmap.recycle()?

python - 如何删除 Python 中对象的每个引用?

android - 如何将 Google Play 帐户链接到 Google 开发者项目

android - 建议用户使用 Google Play 更新 Android 应用(Google 应用内更新支持)

java - G1GC中如何触发Old Generation的回收

c# - 如何清理弱引用集合?

java - Soft-/Weak-/PhantomReferences 清除对跟踪对象的引用的基本原理