Память и Действия :: OutOfMemory - PullRequest
5 голосов
/ 26 января 2012

НАСТРОЙКА:

У меня есть это приложение, которое имеет 4 действия по линейному пути, очень простая навигация: A -> B -> C -> D

Все действия имеют одно и то же фоновое изображение, и у всех есть пара обычных кнопок, текстовое представление или текст редактирования. Все они определены в отдельных XML-файлах представлений.

Фон градиентный и довольно тяжелый. Около 3 мегабайт в виде несжатого растрового изображения.

Приложение пока ничего не делает, единственная логика в нем - запускать действия и закрывать их по нажатию кнопки

Я пытался использовать MAT для обнаружения утечки памяти, но ничего не смог найти. Самый большой оставшийся размер в моем приложении - 656 (КО?). Общий оставшийся размер приложения - 1520 (КО?), И я не могу найти объект, который будет дублирован. Что, кстати, полностью противоречит dumpsys, который показывает 27300 (ко?) Выделенных

ПРОБЛЕМЫ:

  1. Когда я перемещаюсь вверх, я вижу увеличение использования памяти, эквивалентное размеру фона.
  2. Когда я перемещаюсь ВНИЗ, закрывая действия кнопкой «Назад» или командой «Завершить», использование памяти приложением не уменьшается.
  3. Если я перейду от A к D, затем вернусь к B и поверну экран, приложение закроется с исключением OutOfMemory.

ВОПРОСЫ:

Обновление: я предполагаю, что реальный вопрос заключается в том, почему у меня возникает огромная утечка памяти (5 мегабайт за раз) с размером приложения 27 мегабайт во время зависания, и я не вижу его в MAT?

  1. Зачем Android распаковывать несколько раз один и тот же фон, один раз за действие? Кажется неэффективным.
  2. Можно ли преодолеть эту проблему с помощью тем или я увижу ту же странность "выделить 1 фон по активности"?
  3. Почему деятельность не восстанавливается после закрытия?
  4. Почему MAT и dumpsys представляют разные цифры?

КЛЮЧИ

В то же самое время у меня есть: dumpsys meminfo:

Applications Memory Usage (kB):
Uptime: 74006853 Realtime: 110962243

** MEMINFO in pid 22683 [com.kayenko.sosadresse] **
                    native   dalvik    other    total
            size:    20820     5767      N/A    26587
       allocated:    18751     2901      N/A    21652
            free:      312     2866      N/A     3178
           (Pss):     1357      201    16782    18340
  (shared dirty):     2264     1804     5456     9524
    (priv dirty):     1280      116    16032    17428

 Objects
           Views:        0        ViewRoots:        0
     AppContexts:        0       Activities:        0
          Assets:        2    AssetManagers:        2
   Local Binders:       18    Proxy Binders:       16
Death Recipients:        1
 OpenSSL Sockets:        0

 SQL
               heap:        0         MEMORY_USED:        0
 PAGECACHE_OVERFLOW:        0         MALLOC_SIZE:        0

А это дерево-доминатор:

MAT Dominator tree

Спасибо всем, кто знает, что я должен искать.

Ответы [ 3 ]

7 голосов
/ 27 января 2012

Память - очень сложная тема в Android.

Каждое приложение получает ограничение кучи памяти в зависимости от устройства. Эта кучная память - это память dalvik плюс собственная память, и вы можете увидеть ее как итоговый столбец в результатах dumpsys meminfo. Память dalvik имеет дело со всем, кроме растровых изображений, которые размещены в собственной памяти (это верно для версий Android до Honeycomb).

Сказав, что я могу ответить только на некоторые ваши вопросы:

  1. Насколько я знаю, Android всегда будет выделять память для растровых изображений, даже если они одинаковы. Поэтому в вашем случае каждое действие выделяет память для вашего фона.

  2. Я не знаю, лучше ли работать с темами, вам придется это попробовать.

  3. С одной стороны, действия не восстанавливаются, пока на устройстве достаточно памяти, чтобы справиться со следующим действием. Каждое действие помещается в стопку, откуда оно восстанавливается при нажатии кнопки «Назад». В случае, если Android требуется больше памяти, он удаляет одно действие из кучи, освобождая его память (возвращаясь к вопросу номер один, может быть, это причина того, что не делится памятью). С другой стороны, вы можете установить действия launchMode, чтобы изменить это поведение (посмотрите здесь ).

  4. Я думаю, что MAT не показывает данные собственной памяти. Используйте собственный столбец dumpsys meminfo, чтобы увидеть, сколько выделено памяти для растровых изображений.

У меня были трудные времена, когда я сам решал проблемы OutOfMemory. Теперь у меня есть гораздо более четкая идея о том, как это работает, и я могу работать с большими файлами без исчерпания памяти. Я очень рекомендую эти два ресурса, которые мне очень помогли:

Удачи!

4 голосов
/ 27 января 2012

Итак, после нескольких часов исследований и помощи Хави, вот результаты:

Q. Зачем Android распаковывать несколько раз один и тот же фон, один раз за действие? Кажется неэффективным.

A. Даже при том, что было бы логично иметь какой-то способ попросить совместное использование растрового изображения между действиями, поскольку мы работаем на мобильных устройствах с небольшим объемом памяти, в Android этого, похоже, не существует. Каждый раз, когда растровое изображение используется в различных действиях, оно распаковывается в собственную память.

Q. Можно ли решить эту проблему, используя темы, или я увижу ту же странность «выделить один битовый массив по активности»?

После экспериментов память, используемая с использованием тем, совершенно не отличается от объема памяти, используемого путем явной установки растрового изображения в xml макетов. Это странно для меня, так как стилизация заключается в группировании атрибутов в одном месте.

Q. Почему действия не возвращаются после закрытия?

A. Ну, я не уверен, но я обнаружил, что это дало мне ошибки OOM почти только при отладке. При запуске приложения с устройства это почти никогда не происходило. Глюк в процессе отладки? Попробуйте, прежде чем вы потратите 5 часов на тестирование zillion вещь.

Q. Почему MAT и dumpsys представляют разные цифры?

A. Ответ Хави верен, dumpsys meminfo показывает всю выделенную память (native + dalvik), а MAT показывает только Dalvik. Поскольку пиксели растровых изображений размещаются в собственной памяти, MAT не увидит этого. Это верно только до Android 3.0, где они изменили схему размещения и сделали пиксельные данные растрового изображения вписанными в Dalvik.

Q. Как я решил мою проблему

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

getWindow().setFormat(PixelFormat.RGBA_8888);
getWindow().addFlags(WindowManager.LayoutParams.FLAG_DITHER);

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

0 голосов
/ 26 января 2012

Вам необходимо явно переработать растровое изображение, используемое в качестве фона, когда вы уничтожаете свою деятельность.Код будет выглядеть следующим образом:

@Override
protected void onDestroy () {
    Drawable drawable = getView().getBackground();
    if (drawable instanceof BitmapDrawable) {
        ((BitmapDrawable)drawable).getBitmap().recycle();
    }
    drawable.setCallback(null);
    getView().setBackgroundDrawable(null);
    super.onDestroy();
}

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...