10

DalvikのガベージコレクターはSoftReferencesを尊重せず、WeakReferencesと同様に、できるだけ早くそれらを削除します。まだ100%確信はありませんが、まだ最大3MBの空きメモリがあるにもかかわらず、LogCatに「GCがbla-bla-blaバイトを解放しました」と表示された後、SoftReferencesがクリアされます。

また、ここでマーク・マーフィーのコメントを見ました:

少なくとも1.5の時間枠では、Androidでは機能しないことを除いて。GCSoftReferenceのバグが修正されたかどうかはわかりません。SoftReferencesは、このバグですぐにGCされます。

それは本当ですか?SoftReferencesは尊重されていませんか?

これを回避する方法は?

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パスを実行することによって)。

結果は非常に興味深いものです。1つを除いて、すべての実行が問題なく通過します。

Android 1.5デバイスの場合:
testSoftRefsAgainstGc_1()が失敗しました!AssertionFailedError:expected:0しかしwas:499
testSoftRefsAgainstGc_2()に合格
testSoftRefsAgainstGc_3()に合格
testSoftRefsAgainstGc_4()に合格
testSoftRefsAgainstGc_5()に合格
testSoftRefsAgainstGc_6()に合格
testSoftRefsAgainstGc_7()に合格


Android 1.6デバイスの場合:
testSoftRefsAgainstGc_1()に合格
testSoftRefsAgainstGc_2()が失敗しました!AssertionFailedError:expected:0しかしwas: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

この問題をGoogleに報告しました:https ://code.google.com/p/android/issues/detail?id = 20015

于 2011-09-13T17:19:58.040 に答える
1

@JBM Nexus S(android4.2.2)でTestCaseを試しましたが、すべてのテストに失敗しました。GCはandroid4.2.2のSoftReferenceに対してより積極的です

于 2013-07-14T05:11:51.443 に答える