6

タイトルが示すように、レイアウトの読み込み時にメモリ不足の例外がスローされます。これはメモリリークの問題だと思うかもしれませんが、2日間戦った後、私はもう確信が持てません. アプリには 10 以上のアクティビティがあり、そのほとんどに背景画像があります。

私が行ったいくつかの事実/発見:

  • これまでのところ、この問題は Android 4.0.3 を実行している Galaxy Nexus でのみ発生します。Nexus S (4.1.1) と Galaxy S II (2.3.3) では再現できませんでした。

  • 画面の向きは変わりません。実際、私の活動のほとんどはポートレートに固定されています。

  • 笑いのために、新しいアクティビティを開くときに呼び出しを追加しfinish()たので、その時点でメモリに複数のアクティビティが存在することはありません。onDestroyが呼び出されていることを確認しました。

次のように定義されます。

@Override
public void onDestroy()
{
    super.onDestroy();
    cleanupDrawables(contentView);

    // null all the fields referencing views and drawables

    System.gc();
}

どこにcleanupDrawables()ある:

protected static void cleanupDrawables(View view)
{
    cleanupDrawable(view.getBackground());

    if (view instanceof ImageView)
        cleanupDrawable(((ImageView)view).getDrawable());
    else if (view instanceof TextView)
    {
        TextView tv = (TextView)view;
        Drawable[] compounds = tv.getCompoundDrawables();
        for (int i = 0; i < compounds.length; i++)
            cleanupDrawable(compounds[i]);
    }
    else if (view instanceof ViewGroup && !(view instanceof AdapterView))
    {
        ViewGroup vg = (ViewGroup)view;
        for (int i = 0; i < vg.getChildCount(); i++)
            cleanupDrawables(vg.getChildAt(i));
        vg.removeAllViews();
    }
}

protected static void cleanupDrawable(Drawable d)
{
    if (d == null)
        return;

    d.setCallback(null);

    if (d instanceof BitmapDrawable)
        ((BitmapDrawable)d).getBitmap().recycle();
    else if (d instanceof LayerDrawable)
    {
        LayerDrawable layers = (LayerDrawable)d;
        for (int i = 0; i < layers.getNumberOfLayers(); i++)
            cleanupDrawable(layers.getDrawable(i));
    }
}
  • Eclipse ヒープ インスペクタを見ると、メモリは安定しているように見えます。つまり、一部のアクティビティは他のアクティビティよりも多くのメモリを消費しますが、閉じると解放され、時間の経過とともに安定しているように見えます。

  • SO に関する関連する回答によると、イメージはネイティブ メモリに保存されますが、この男は Android 3 以降、ヒープ上にある必要があると主張しているため、これが実際にイメージ メモリ リークである場合、メモリの増加が見られるはずです。

私の努力の最終結果は、以前ほど速くはありませんが、依然としてメモリ不足エラーが発生することです。cleanupDrawables()エラーが発生する前に、コードを追加する前はそうではなかった目に見えるビットマップの破損が見られるようになりました。Bitmap.recycle()このコードは でのみ呼び出されますが、 への呼び出しが破損を引き起こしていると推測しましたonDestroy。破損は、多くのアクティビティに表示される一般的なスタイルの一部であるビットマップと、1 つのアクティビティにのみ表示されるビットマップの両方に表示されます。

要するに、私の調査結果はかなり決定的ではありません。この時点で、他に何を試すべきかわかりません。

参照用のエラー スタック トレース:

08-22 10:49:51.889: E/AndroidRuntime(31697): java.lang.RuntimeException: Unable to start activity ComponentInfo{klick.beatbleeds/klick.beatbleeds.Bleeds}: android.view.InflateException: Binary XML file line #67: Error inflating class <unknown>
08-22 10:49:51.889: E/AndroidRuntime(31697):    at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:1955)
08-22 10:49:51.889: E/AndroidRuntime(31697):    at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:1980)
08-22 10:49:51.889: E/AndroidRuntime(31697):    at android.app.ActivityThread.access$600(ActivityThread.java:122)
08-22 10:49:51.889: E/AndroidRuntime(31697):    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1146)
08-22 10:49:51.889: E/AndroidRuntime(31697):    at android.os.Handler.dispatchMessage(Handler.java:99)
08-22 10:49:51.889: E/AndroidRuntime(31697):    at android.os.Looper.loop(Looper.java:137)
08-22 10:49:51.889: E/AndroidRuntime(31697):    at android.app.ActivityThread.main(ActivityThread.java:4340)
08-22 10:49:51.889: E/AndroidRuntime(31697):    at java.lang.reflect.Method.invokeNative(Native Method)
08-22 10:49:51.889: E/AndroidRuntime(31697):    at java.lang.reflect.Method.invoke(Method.java:511)
08-22 10:49:51.889: E/AndroidRuntime(31697):    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:784)
08-22 10:49:51.889: E/AndroidRuntime(31697):    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:551)
08-22 10:49:51.889: E/AndroidRuntime(31697):    at dalvik.system.NativeStart.main(Native Method)
08-22 10:49:51.889: E/AndroidRuntime(31697): Caused by: android.view.InflateException: Binary XML file line #67: Error inflating class <unknown>
08-22 10:49:51.889: E/AndroidRuntime(31697):    at android.view.LayoutInflater.createView(LayoutInflater.java:606)
08-22 10:49:51.889: E/AndroidRuntime(31697):    at com.android.internal.policy.impl.PhoneLayoutInflater.onCreateView(PhoneLayoutInflater.java:56)
08-22 10:49:51.889: E/AndroidRuntime(31697):    at android.view.LayoutInflater.onCreateView(LayoutInflater.java:653)
08-22 10:49:51.889: E/AndroidRuntime(31697):    at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:678)
08-22 10:49:51.889: E/AndroidRuntime(31697):    at android.view.LayoutInflater.rInflate(LayoutInflater.java:739)
08-22 10:49:51.889: E/AndroidRuntime(31697):    at android.view.LayoutInflater.inflate(LayoutInflater.java:489)
08-22 10:49:51.889: E/AndroidRuntime(31697):    at android.view.LayoutInflater.inflate(LayoutInflater.java:396)
08-22 10:49:51.889: E/AndroidRuntime(31697):    at android.view.LayoutInflater.inflate(LayoutInflater.java:352)
08-22 10:49:51.889: E/AndroidRuntime(31697):    at klick.beatbleeds.ActivityBase.setContentView(ActivityBase.java:82)
08-22 10:49:51.889: E/AndroidRuntime(31697):    at klick.beatbleeds.Bleeds.onCreate(Bleeds.java:40)
08-22 10:49:51.889: E/AndroidRuntime(31697):    at android.app.Activity.performCreate(Activity.java:4465)
08-22 10:49:51.889: E/AndroidRuntime(31697):    at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1049)
08-22 10:49:51.889: E/AndroidRuntime(31697):    at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:1919)
08-22 10:49:51.889: E/AndroidRuntime(31697):    ... 11 more
08-22 10:49:51.889: E/AndroidRuntime(31697): Caused by: java.lang.reflect.InvocationTargetException
08-22 10:49:51.889: E/AndroidRuntime(31697):    at java.lang.reflect.Constructor.constructNative(Native Method)
08-22 10:49:51.889: E/AndroidRuntime(31697):    at java.lang.reflect.Constructor.newInstance(Constructor.java:417)
08-22 10:49:51.889: E/AndroidRuntime(31697):    at android.view.LayoutInflater.createView(LayoutInflater.java:586)
08-22 10:49:51.889: E/AndroidRuntime(31697):    ... 23 more
08-22 10:49:51.889: E/AndroidRuntime(31697): Caused by: java.lang.OutOfMemoryError
08-22 10:49:51.889: E/AndroidRuntime(31697):    at android.graphics.Bitmap.nativeCreate(Native Method)
08-22 10:49:51.889: E/AndroidRuntime(31697):    at android.graphics.Bitmap.createBitmap(Bitmap.java:605)
08-22 10:49:51.889: E/AndroidRuntime(31697):    at android.graphics.Bitmap.createBitmap(Bitmap.java:551)
08-22 10:49:51.889: E/AndroidRuntime(31697):    at android.graphics.Bitmap.createScaledBitmap(Bitmap.java:437)
08-22 10:49:51.889: E/AndroidRuntime(31697):    at android.graphics.BitmapFactory.finishDecode(BitmapFactory.java:524)
08-22 10:49:51.889: E/AndroidRuntime(31697):    at android.graphics.BitmapFactory.decodeStream(BitmapFactory.java:499)
08-22 10:49:51.889: E/AndroidRuntime(31697):    at android.graphics.BitmapFactory.decodeResourceStream(BitmapFactory.java:351)
08-22 10:49:51.889: E/AndroidRuntime(31697):    at android.graphics.drawable.Drawable.createFromResourceStream(Drawable.java:773)
08-22 10:49:51.889: E/AndroidRuntime(31697):    at android.content.res.Resources.loadDrawable(Resources.java:1937)
08-22 10:49:51.889: E/AndroidRuntime(31697):    at android.content.res.TypedArray.getDrawable(TypedArray.java:601)
08-22 10:49:51.889: E/AndroidRuntime(31697):    at android.view.View.<init>(View.java:2780)
08-22 10:49:51.889: E/AndroidRuntime(31697):    at android.view.ViewGroup.<init>(ViewGroup.java:385)
08-22 10:49:51.889: E/AndroidRuntime(31697):    at android.widget.LinearLayout.<init>(LinearLayout.java:174)
08-22 10:49:51.889: E/AndroidRuntime(31697):    at android.widget.LinearLayout.<init>(LinearLayout.java:170)
08-22 10:49:51.889: E/AndroidRuntime(31697):    ... 26 more

ここで使用されている画像の数を把握するためのビューの 1 つのスクリーンショットを次に示します。 ここに画像の説明を入力

4

1 に答える 1

2

これらの静的メソッドを使用して、正確な問題を見つけます。

public static void showBitmapSize(Bitmap bitmap) {
    Log.d("test", "bitmap dimensions: w:" + bitmap.getWidth() + ", h:" + bitmap.getHeight() + " memory: " + (bitmap.getRowBytes() * bitmap.getHeight() / 1048576d));
}

そして最も重要なのは:

static double lastavail;
static double initavail;
static boolean first = true;

public static void showMemoryStats() {
    showMemoryStats("");
}

public static void showMemoryStats(String message) {
    Log.i("memory", message + "----------------------------------------------------------------------------------------");
    double nativeUsage = Debug.getNativeHeapAllocatedSize(); 
    Log.i("memory", "nativeUsage: " + (nativeUsage / 1048576d));
    //current heap size 
    double heapSize =  Runtime.getRuntime().totalMemory();
//      Log.i("memory", "heapSize: " + (heapSize / 1048576d));
    //amount available in heap 
    double heapRemaining = Runtime.getRuntime().freeMemory();
//      Log.i("memory", "heapRemaining: " + (heapRemaining / 1048576d)); 
    double memoryAvailable = Runtime.getRuntime().maxMemory() - (heapSize - heapRemaining) - nativeUsage;
    Log.i("memory", "memoryAvailable: " + (memoryAvailable / 1048576d));

    if (first) {
        initavail = memoryAvailable;
        first = false;
    }
    if (lastavail > 0) {
        Log.i("memory", "consumed since last: " + ((lastavail - memoryAvailable) / 1048576d));
    }
    Log.i("memory", "consumed total: " + ((initavail - memoryAvailable) / 1048576d));

    lastavail = memoryAvailable;

    Log.i("memory", "-----------------------------------------------------------------------------------------------");
}

1048576で割ると、値をMBで取得するだけです(少なくとも私にとっては、MBで考える方が簡単です)。

showMemoryStats呼び出しの前に意味のあるメッセージを付けて呼び出しを行い、呼び出しsetContentView()の後に別のメッセージを入れます。そして、あなたが新しい活動を始めるときなど。最後にあなたはあなたの問題の正確な理由を知るでしょう。

手動でのリサイクルが必要になる場合があります。アプリのいくつかの場所に実装する必要がありました。また、ビットマップを多用するもの(多くの背景と写真)を使用しており、すべてのデバイスでこの種の問題が発生していました。これらの方法で、私はすべての問題を見つけて適切に処理することができました。

ああ。そして、あなたの問題に対する可能な速い解決策があります、あなたはそれがギャラクシーネクサスでのみ現れると言います。それはあなたが言及したものの中で唯一のxhdpiデバイスです。おそらく、すべてのビットマップは、フォルダーdrawableまたはdrawable-hdpiにのみ存在します。xhdpiデバイスは、drawableまたはdrawable-hdpiからビットマップを取得してスケールアップします(ただし、既に正しいサイズになっている可能性があります)。これにより、大量のメモリが消費されます。解決策:drawable-xhdpiフォルダーが存在しない場合は作成し、そこにビットマップのコピーを配置します。

于 2012-08-22T17:27:11.673 に答える