Android: the GC doesn't respect SoftReferences?

后端 未结 3 1913
悲哀的现实
悲哀的现实 2021-02-06 00:19

It seams that Dalvik\'s garbage collector doesn\'t respect SoftReferences and removes them as soon as possible, just like WeakReferences. I\'m not 100% sure yet, but despite the

相关标签:
3条回答
  • 2021-02-06 00:49

    After not receiving an answer I decided to make my own study. I've made a simple test to exercise the GC against SoftReferences.

    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);
        }
    }
    

    The idea is that I make few runs of the same code increasing stress on SoftReferences each time (by running more GC passes).

    Results are pretty interesting: All runs pass just fine except for one!

    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.
    

    These test results are stable. I've tried many times and every time it is the same. So I believe it is indeed a bug in garbage collector.

    CONCLUSION

    So, what we learn out of this... Using SoftReferences in your code is pointless for Android 1.5-1.6 devices. For these devices you will not get the behavior you expect. I didn't try for 2.1, however.

    0 讨论(0)
  • 2021-02-06 01:00

    @JBM I've tried your TestCase on Nexus S (android4.2.2), all tests are failed. GC is more aggressive against SoftReference on android4.2.2

    0 讨论(0)
  • 2021-02-06 01:03

    I reported this issue to Google: https://code.google.com/p/android/issues/detail?id=20015

    0 讨论(0)
提交回复
热议问题