2012-08-22 19 views
6

Как говорится в заголовке, у меня есть исключение из памяти, которое бросается при загрузке макетов. Можно было бы подумать, что это проблема утечки памяти, но после битвы в течение 2 дней я больше не уверен. Приложение имеет 10+ видов деятельности, большинство из которых имеют фоновые изображения.OutOfMemoryError создает растровые изображения

Несколько фактов/открытия я сделал:

  • до сих пор проблема появляется только на Galaxy Nexus работает Android 4.0.3. Я не смог воспроизвести его на 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)); 
    } 
} 
  • глядя на кучу инспектора Затмения, память, как представляется, быть стабильным, то есть некоторые виды деятельности занимают больше памяти чем другие, но он выпущен после закрытия, и со временем он выглядит стабильным.

  • в соответствии с соответствующими ответами на изображениях SO хранятся в собственной памяти, но this чувак утверждает, что они должны находиться на куче с Android 3, поэтому я должен увидеть увеличение памяти, если это действительно было утечкой памяти изображения.

Конечный результат моих усилий состоит в том, что я по-прежнему выхожу из памяти, хотя и не так быстро, как раньше. Перед возникновением ошибки я начинаю видеть видимое повреждение растрового изображения, чего не было до того, как я добавил код cleanupDrawables(). Я пришел к выводу, что вызов Bitmap.recycle() вызывает повреждение, хотя этот код вызывается только onDestroy. Коррупция появляется на обоих растровых изображениях, которые являются частями общих стилей, появляющихся во многих действиях, а также растровые изображения, показанные только в одном действии.

Вкратце результаты моих исследований довольно неубедительны. На данный момент я не знаю, что еще попробовать.

стек ошибок трассировки для справки:

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

И самое главное:

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 только для получения значений в МБ (по крайней мере, для меня легче думать в МБ).

Позвоните по телефону showMemoryStats с каким-либо значимым сообщением перед вызовом setContentView() и еще одним после него. И когда вы начинаете новую деятельность и т. Д. В конце вы найдете точные причины своей проблемы.

Может потребоваться ручная утилизация. Я должен был реализовать его в некоторых местах своего приложения. Кроме того, с использованием интенсивно-растрового изображения (много фонов и рисунков) и возникли такие проблемы на всех устройствах. С помощью этих методов я смог найти все проблемы и справиться с ними.

Ах. И есть возможное быстрое решение вашей проблемы, вы говорите, что оно появляется только в Galaxy Nexus. Это единственное устройство xhdpi, которое вы упомянули. Возможно, у вас есть все растровые изображения только в папке drawable или drawable-hdpi. Устройство xhdpi будет принимать растровые изображения от drawable или drawable-hdpi и масштабироваться (хотя они могут быть уже в правильном размере), и это будет потреблять много памяти. Решение. Создайте папку drawable-xhdpi, если она не существует, и поместите туда копии растровых изображений.

Смежные вопросы