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