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

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



是真的吗是否不遵守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传递)。

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

在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。

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

10-09 05:48