10

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

另外,我在这里看到了 Mark Murphy 的评论:

除了它不能在 Android 上运行,至少在 1.5 时间范围内。我不知道 GC SoftReference 错误是否已修复。SoftReferences 很快就会因为这个错误而被 GC。

这是真的吗?是否不尊重软引用?

如何解决这个问题?

4

3 回答 3

7

在没有收到答案后,我决定自己研究。我做了一个简单的测试来针对 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 传递)。

结果非常有趣:所有运行都通过了,除了一个!

在 Android 1.5 设备上:
testSoftRefsAgainstGc_1() 失败!AssertionFailedError:预期:0 但为:499
testSoftRefsAgainstGc_2() 通过
testSoftRefsAgainstGc_3() 通过
testSoftRefsAgainstGc_4() 通过
testSoftRefsAgainstGc_5() 通过
testSoftRefsAgainstGc_6() 通过
testSoftRefsAgainstGc_7() 通过


在 Android 1.6 设备上:
testSoftRefsAgainstGc_1() 通过
testSoftRefsAgainstGc_2() 失败!AssertionFailedError:预期:0 但为:499
testSoftRefsAgainstGc_3() 通过
testSoftRefsAgainstGc_4() 通过
testSoftRefsAgainstGc_5() 通过
testSoftRefsAgainstGc_6() 通过
testSoftRefsAgainstGc_7() 通过

在 Android 2.2 设备上:
全部通过。

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

结论

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

于 2010-10-30T12:39:07.243 回答
1

@JBM我在Nexus S(android4.2.2)上试过你的TestCase,所有测试都失败了。GC 对 android4.2.2 上的 SoftReference 更具攻击性

于 2013-07-14T05:11:51.443 回答
1

我向谷歌报告了这个问题:https ://code.google.com/p/android/issues/detail?id=20015

于 2011-09-13T17:19:58.040 回答