2012-08-22 17 views
6

タイトルのとおり、レイアウトの読み込み時にメモリ不足例外が発生しています。これはメモリリークの問題だと思うかもしれませんが、2日間それと戦った後、私はもうこれ以上確かではありません。アプリには10以上のアクティビティがあり、そのほとんどに背景イメージがあります。ビットマップを作成するOutOfMemoryError

  • これまでのところ問題は唯一のAndroid 4.0.3を実行しているギャラクシーネクサスに表示されます:私が作った

    いくつかの事実/発見。 Nexus S(4.1.1)とGalaxy S II(2.3.3)で再現できませんでした。

  • 画面の向きは変わりません。実際、私の活動のほとんどはとにかく肖像画にロックされていました。

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

    cleanupDrawables()がある
    @Override 
    public void onDestroy() 
    { 
        super.onDestroy(); 
        cleanupDrawables(contentView); 
    
        // null all the fields referencing views and drawables 
    
        System.gc(); 
    } 
    

    Eclipseのヒープインスペクタを見て
    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)); 
        } 
    } 
    
    • いくつかの活動がより多くのメモリを取る。すなわち、メモリは、安定したように見えるように定義

    閉鎖時に解放され、時間の経過とともに安定しているように見えます。

  • SO画像の関連回答によれば、thisは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 

ここでは、ここで enter image description here

+0

これらのビットマップ(解像度)はどれくらい大きいのですか?より小さなイメージ(ちょうどキックのためのもの)でそれらを置き換えるならば、問題は消えますか? – dmon

+0

ビューからビットマップリソースをクリーンアップする必要はなく、新しいアクティビティへの移行が遅くなります。あなたはどのようなレイアウトのイメージを膨らませていますか? – DeeV

+0

私は@Deevにも同意します。破棄時に手動でビットマップをクリーンアップする必要はありません。 – dmon

答えて

2

見つけるために、これらの静的メソッドを使用して使用されているどのように多くの画像のアイデアを得るためのビューのいずれかのスクリーンショットです

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

そして、最も重要:

正確な問題(S)アウト
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()コールの前にいくつか意味のあるメッセージを、もう1つ後にコールします。あなたが新しい活動などを始めるときに、あなたはあなたの問題の正確な理由を最後にします。

マニュアルリサイクルが必要な場合があります。私はアプリのいくつかの場所でそれを実装しなければなりませんでした。また、ビットマップ集約的なもの(多くの背景や写真)を使用し、すべてのデバイスでこの種の問題を抱えていました。これらの方法で私はすべての問題を見つけ出し、適切に処理することができました。

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

関連する問題