Android:GC不尊重SoftReferences?

时间:2010-10-25 11:19:20

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

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

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

  

除非它不起作用   Android,至少在1.5   大体时间。我不知道GC   SoftReference错误已得到修复。   SoftReferences很快就会得到GC   这个错误。

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

如何解决这个问题?

3 个答案:

答案 0 :(得分: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传递)。

结果非常有趣:除了一个之外,所有的跑步都很好!

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。

答案 1 :(得分:1)

答案 2 :(得分:1)

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