Подтвердить что ты не робот

Ошибка OutOfMemory, хотя имеется свободная память.

Я вижу довольно странную проблему. По сути, иногда большие битмап-памяти не срабатывают, хотя, по-видимому, объем памяти. Есть несколько сообщений, которые, похоже, задают аналогичный вопрос, но все они связаны с предварительно сотовым андроидом. Я понимаю, что изображения теперь выделены в кучу, а не какая-то внешняя память. В любом случае, посмотрите этот журнал ниже:

    10-14 13:43:53.020: INFO/dalvikvm-heap(31533): Grow heap (frag case) to 40.637MB for 942134-byte allocation
    10-14 13:43:53.070: DEBUG/dalvikvm(31533): GC_FOR_ALLOC freed 126K, 11% free 41399K/46343K, paused 31ms
    10-14 13:43:53.130: DEBUG/dalvikvm(31533): GC_FOR_ALLOC freed 920K, 13% free 40478K/46343K, paused 30ms
    10-14 13:43:53.180: DEBUG/dalvikvm(31533): GC_FOR_ALLOC freed 1026K, 13% free 40479K/46343K, paused 30ms
    10-14 13:43:53.250: DEBUG/dalvikvm(31533): GC_FOR_ALLOC freed 931K, 12% free 41193K/46343K, paused 31ms
    10-14 13:43:53.250: INFO/dalvikvm-heap(31533): Grow heap (frag case) to 41.313MB for 1048592-byte allocation
    10-14 13:43:53.280: DEBUG/dalvikvm(31533): GC_FOR_ALLOC freed <1K, 11% free 42217K/47431K, paused 31ms
    10-14 13:44:01.520: DEBUG/dalvikvm(31533): GC_CONCURRENT freed 3493K, 15% free 40646K/47431K, paused 3ms+9ms
    10-14 13:44:08.130: DEBUG/dalvikvm(31533): GC_EXPLICIT freed 16461K, 47% free 25527K/47431K, paused 3ms+6ms
    10-14 13:44:09.150: DEBUG/dalvikvm(31533): GC_FOR_ALLOC freed 1007K, 45% free 26191K/47431K, paused 35ms
    10-14 13:44:09.160: INFO/dalvikvm-heap(31533): Grow heap (frag case) to 29.334MB for 3850256-byte allocation
    10-14 13:44:09.200: DEBUG/dalvikvm(31533): GC_CONCURRENT freed 0K, 37% free 29951K/47431K, paused 2ms+4ms
    10-14 13:44:11.970: DEBUG/dalvikvm(31533): GC_FOR_ALLOC freed 1878K, 38% free 29784K/47431K, paused 37ms
    10-14 13:44:12.410: DEBUG/dalvikvm(31533): GC_FOR_ALLOC freed 62K, 36% free 30441K/47431K, paused 32ms
    10-14 13:44:12.440: DEBUG/dalvikvm(31533): GC_FOR_ALLOC freed <1K, 32% free 32325K/47431K, paused 32ms
    10-14 13:44:12.440: INFO/dalvikvm-heap(31533): Forcing collection of SoftReferences for 3850256-byte allocation
    10-14 13:44:12.480: DEBUG/dalvikvm(31533): GC_BEFORE_OOM freed 124K, 33% free 32200K/47431K, paused 37ms
    10-14 13:44:12.480: ERROR/dalvikvm-heap(31533): Out of memory on a 3850256-byte allocation.

Извиняюсь за то, что вы включили столько протоколов, я надеюсь, что это уместно. То, как я его читаю, заключается в том, что система непрерывно корректирует размер кучи, пока она не достигнет максимума кучи. Затем мы запрашиваем особо большое выделение, которое терпит неудачу. Очевидно, что доступно более чем достаточно памяти (около 15 мегабайт). Означает ли это, что куча внутренне фрагментирована и нет смежных сегментов памяти, достаточно больших для обработки нашего распределения? Если это так, что мне делать? Если это не так, то что?

Спасибо заранее.

4b9b3361

Ответ 1

Странное поведение связано с тем, что растровые изображения выделяются на нативной куче, а не на собранном мусоре, но андроид может отслеживать объекты только в собранной кучей мусора. Из Android 2.2 (или 2.3, возможно) это изменилось, и выделенные растровые изображения также видны, если вы сделали кучу кучи.

Вернемся к вопросу, скорее всего, ваша проблема связана с тем, что битмапы, загруженные вручную, не освобождаются должным образом. Одна из типичных проблем заключается в том, что некоторая обратная связь остается установленной или вид по-прежнему ссылается на растровое изображение. Другая распространенная проблема заключается в том, что если вы загружаете большие растровые изображения вручную (а не как ресурс), вам нужно будет вызвать recycle() на них, когда вам это больше не понадобится, что освободит растровое изображение из встроенной памяти, чтобы мусор коллекционер сможет работать, как должен. (GC только видит объекты в куче GC и не имеет никакого объекта для освобождения свободной памяти от нативной кучи и на самом деле даже не заботится об этом.)

У меня есть этот маленький ребенок под рукой все время:

public static void stripImageView(ImageView view) {
    if ( view.getDrawable() instanceof BitmapDrawable ) {
        ((BitmapDrawable)view.getDrawable()).getBitmap().recycle();
    }
    view.getDrawable().setCallback(null);
    view.setImageDrawable(null);
    view.getResources().flushLayoutCache();
    view.destroyDrawingCache();
}

Ответ 2

Изображения извлекаются из Интернета, каждый в диапазоне от 300 К до 500 К в размер и хранится в массивеList из Drawables.

Размер файла kb для изображения, загружаемого из Интернета, не имеет прямого отношения. Поскольку они преобразуются в растровые изображения, вам нужно рассчитать ширину * высота * 4 байта на изображение для обычных изображений ARGB. (ширина и высота в пикселях).

Растровые изображения потребляют встроенную кучу, которая обычно не отображается в hprof. Hprof должен показывать только количество объектов, то есть BitmapDrawables или растровые изображения, которые остались.

Я использую этот код в своем приложении для вывода текущей используемой памяти, используемой приложением и нативной кучей:

public static void logHeap(Class clazz) {
    Double allocated = new Double(Debug.getNativeHeapAllocatedSize())/new Double((1048576));
    Double available = new Double(Debug.getNativeHeapSize())/1048576.0);
    Double free = new Double(Debug.getNativeHeapFreeSize())/1048576.0);
    DecimalFormat df = new DecimalFormat();
    df.setMaximumFractionDigits(2);
    df.setMinimumFractionDigits(2);

    Log.d(APP, "debug. =================================");
    Log.d(APP, "debug.heap native: allocated " + df.format(allocated) + "MB of " + df.format(available) + "MB (" + df.format(free) + "MB free) in [" + clazz.getName().replaceAll("com.myapp.android.","") + "]");
    Log.d(APP, "debug.memory: allocated: " + df.format(new Double(Runtime.getRuntime().totalMemory()/1048576)) + "MB of " + df.format(new Double(Runtime.getRuntime().maxMemory()/1048576))+ "MB (" + df.format(new Double(Runtime.getRuntime().freeMemory()/1048576)) +"MB free)");
    System.gc();
    System.gc();

    // don't need to add the following lines, it just an app specific handling in my app        
    if (allocated>=(new Double(Runtime.getRuntime().maxMemory())/new Double((1048576))-MEMORY_BUFFER_LIMIT_FOR_RESTART)) {
        android.os.Process.killProcess(android.os.Process.myPid());
    }
}

который я вызываю при запуске или завершении операции во время разработки.

logHeap(this.getClass());

Вот некоторые информативные ссылки - как правило, здесь есть много тем, посвященных этой теме.

Здесь также полезный слайд Romain Guy (разработчик Android Framework) о мягких ссылках, слабых ссылках, простых кешах, обработке изображений: http://docs.huihoo.com/google/io/2009/Th_0230_TurboChargeYourUI-HowtomakeyourAndroidUIfastandefficient.pdf

Ответ 3

да, ошибка "вне памяти" возникает, когда мы работаем с растровым изображением большого размера. для этого у меня есть решение, с декодированием изображения мы можем легко избежать этой ошибки.

BitmapFactory.Options o = new BitmapFactory.Options();
o.inJustDecodeBounds = true;
FileInputStream fis = new FileInputStream(files.getAbsolutePath());
BitmapFactory.decodeStream(fis, null, o);
fis.close();
final int REQUIRED_SIZE=70;
int width_tmp=o.outWidth, height_tmp=o.outHeight;
int scale=1;
while(true){
if(width_tmp/2<REQUIRED_SIZE || height_tmp/2<REQUIRED_SIZE)
break;
width_tmp/=2;
height_tmp/=2;
scale*=2;
}
BitmapFactory.Options op = new BitmapFactory.Options();
op.inSampleSize = scale;
fis = new FileInputStream(files.getAbsolutePath());
bitmap[i] = BitmapFactory.decodeStream(fis, null, op);
fis.close();

Ответ 4

Система не корректирует размеры кучи. Ваше приложение имеет (полу) предопределенное кучу пространства. Размеры кучи можно отрегулировать в некоторых пользовательских ПЗУ. Это действительно не связано с вашей проблемой.

Порядок сбора мусора, который вы видите, кажется, предполагает, что во время GC_BEFORE_OOM ваше приложение выйдет из своего кучного пространства. Статистика, зарегистрированная регистратором Dalvik, может быть общесистемной.