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

Контекстная память Android Context Memory List из-за AudioManager

У меня есть ListView, и я ожидаю, что он будет очищен из памяти, когда закончится действие. Однако, похоже, он протекает. Когда я проверяю Дамп памяти и получаю pathToGC для ListView, я получаю следующее:

Class Name                                                          | Shallow Heap | Retained Heap 
android.widget.ExpandableListView @ 0x4063e560                      |          768 |        39,904 
|- list, mList com.hitpost.TeamChooser @ 0x405f92e8                 |          176 |         1,648 
|  '- mOuterContext android.app.ContextImpl @ 0x40657368            |          160 |           304 
|     '- mContext android.media.AudioManager @ 0x40662600           |           40 |           168 
|        '- this$0 android.media.AudioManager$1 @ 0x406626b0 Unknown|           24 |            24 

Я вижу, что этот же контекст просачивается во многие мои ListView's. Хитрость в том, что я вообще не использую AudioManager где-либо в своем приложении, никакого звука из приложения вообще нет. Пожалуйста, помогите, это сводит меня с ума. Очевидно, пытаясь понять, почему это происходит и какова может быть главная проблема?

4b9b3361

Ответ 1

Не связано с утечкой OP, но для людей, которые приходят сюда из-за того, что AudioManager вызывает утечку:

Если вы видите эту утечку, потому что используете VideoView, возможно, из-за этой ошибки: https://code.google.com/p/android/issues/detail?id=152173

VideoView никогда не отпускает AudioManager, если загружается видео.

исправление, как упоминалось в ссылке, создает VideoView вручную с помощью ApplicationContext.

Изменить: эта работа будет работать, пока... если видеодекодер говорит, что у видео есть проблема с кодировкой. VideoView пытается открыть AlertDialog с использованием контекста приложения. Затем происходит авария.

Единственная работа, вокруг которой я могу думать, - сохранить создание видеообзора с использованием контекста активности, а в activity.onDestroy - установить контекст приложения контекста приложения в контекст приложения с помощью отражения.

Примечание: нужно получить AudioManager, используя activity.getSystemService(Context.AUDIO_SERVICE), а не activity.getApplicationContext.getSystemService(Context.AUDIO_SERVICE), поскольку AudioManager является переменной-членом Context (вы получите неправильный экземпляр AudioManager, если вы получить его из контекста приложения).

Наконец, вы можете задаться вопросом, почему переменная-член (AudioManager) мешает классу (Activity) собирать мусор. Из анализатора памяти он показывает, что AudioManager принадлежит собственному стеку. Так что AudioManager каким-то образом не очистился должным образом.

Ответ 2

В вашем коде есть несколько ссылок на AudioManager, которые вы не создаете активно. Например. для каждого кликабельного View может быть один для воспроизведения звуков на экране [source]. Я предполагаю, что это ссылка.

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

Причиной утечки может быть то, что вы удерживаете объект View в коде ListView (Adapter?). Если вы их сохраните, вы можете иметь View, у которого есть ссылка AudioManager и которая хранит ссылку Context)

Ответ 4

В этом случае вы можете использовать контекст приложения, чтобы избежать утечек. Я не знаю, почему, но когда я начал использовать контекст приложения, проблема исчезла.

Ответ 5

Наиболее распространенная причина, по которой я нашел в своем приложении, была связана с инициализацией некоторых компонентов через XML файл. Когда вы это делаете, вводится Activity Context, но иногда все, что вам нужно, это ApplicationContext. Что касается веб-представления в Android, этот метод очень помог мне.

Ответ 6

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

Для этих действий я получал то же, что упоминалось выше в отчете hprof.

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

Ответ 7

Это очень простой вид, который реплицирует проблему (по крайней мере на Android 4.0.3)

public class MainActivity extends Activity {

    int image[];

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        // setContentView(R.layout.activity_main);
        image = new int[1000 * 1500 * 4];
    }
}

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

Теперь, после того, как несколько (5-7 в зависимости от вашего heapSize) перезапускают это действие, генерирует java.lang.OutOfMemoryError при попытке создать новый массив.

07-27 19:54:10.160  22542-22542/? D/dalvikvm﹕ GC_FOR_ALLOC freed 6K, 1% free 56040K/56391K, paused 25ms
07-27 19:54:10.190  22542-22542/? D/dalvikvm﹕ GC_BEFORE_OOM freed 23449K, 43% free 32591K/56391K, paused 30ms
07-27 19:54:10.260  22542-22543/? D/dalvikvm﹕ GC_CONCURRENT freed 0K, 1% free 56029K/56391K, paused 3ms+3ms
07-27 19:54:11.850  22542-22542/? D/dalvikvm﹕ GC_FOR_ALLOC freed 6K, 1% free 56040K/56391K, paused 20ms
07-27 19:54:11.880  22542-22542/? D/dalvikvm﹕ GC_BEFORE_OOM freed <1K, 1% free 56040K/56391K, paused 29ms
... Out of memory on a 24000016-byte allocation.

Dumping.hprof Я также видел 2 действия, один из которых удерживается AudioManager.

Вызов "Обновить кучу", а затем сбор мусора в Android Device Monitor действительно удаляет активность из памяти, это то, что logcat указывает на эту процедуру

07-27 19:44:23.150        85-85/? I/DEBUG﹕ #06  pc 000382cc  /system/lib/libdvm.so (dvmCollectGarbageInternal(GcSpec const*)+1204)

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

Мне кажется, что это ошибка в Android. Обходным путем было бы прямое обращение к изображению = null в OnStop() или onFinish() активности. Это, конечно, не удобно.

Ответ 8

Если ваше приложение вылетает из-за утечки памяти, вы можете избежать этого сбоя, используя try-catch (java.lang.outofmemory). Дело в том, что GC вызывается самим JVM, поэтому программист не имеет никакого контроля над этим. Вы можете установить приложение на SD-карту, в этом случае будет использоваться память SD-карты. Утечка памяти не произойдет.

Просто перейдите в файл манифеста, там должна быть версия no. имя версии, также должно быть "Установить местоположение", сделать его "preferExternal".