Какие инструменты и методы Android лучше всего подходят для поиска утечек памяти/ресурсов?

У меня есть разработанное приложение для Android, и я нахожусь в стадии разработки приложения для телефона, когда все вроде бы работает хорошо, и вы хотите объявить о победе и отправить, но вы знаете, что просто должны быть некоторые утечки памяти и ресурсов там; и на Android всего 16 МБ кучи, и ее, по-видимому, на удивление легко утечь в приложение для Android.

Я осмотрелся и пока смог найти только информацию о «hprof» и «traceview», и ни один из них не получил много положительных отзывов.

С какими инструментами или методами вы столкнулись или разработали и хотите поделиться, возможно, в проекте ОС?


person jottos    schedule 18.07.2009    source источник
comment
Могу ли я проголосовать за то, чтобы Р̀СТȢѸ́ФХѾЦЧШЩЪЫЬѢѤЮѦѪѨѬѠѺѮѰѲѴ изменила свое имя на что-то удобочитаемое.   -  person JPM    schedule 11.02.2015
comment
можно ли снова открыть этот вопрос, если мы удалим слово Android Tools из заголовка вопроса? Ответы, найденные здесь, были весьма полезны для решения моих проблем с утечкой памяти.   -  person k3b    schedule 05.07.2015
comment
Итак, у меня есть пользователь, который постоянно переключается между действиями, то есть он может переключать 15 действий за 20 секунд. Может ли это быть причиной ошибки нехватки памяти? Что мне делать, чтобы это исправить? Спасибо!   -  person Ruchir Baronia    schedule 05.01.2016


Ответы (7)


Одной из наиболее распространенных ошибок, которые я обнаружил при разработке приложений для Android, является ошибка «java.lang.OutOfMemoryError: размер растрового изображения превышает бюджет виртуальной машины». Я часто обнаруживал эту ошибку в действиях, использующих множество растровых изображений после изменения ориентации: действие уничтожается, создается снова, а макеты «раздуваются» из XML, потребляющего память виртуальной машины, доступную для растровых изображений.

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

Сначала установите атрибут «id» в родительском представлении вашего XML-макета:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="fill_parent"
     android:layout_height="fill_parent"
     android:id="@+id/RootView"
     >
     ...

Затем в методе onDestroy() вашей Activity вызовите метод unbindDrawables(), передав ссылку на родительский View, а затем выполните System.gc()

@Override
protected void onDestroy() {
    super.onDestroy();

    unbindDrawables(findViewById(R.id.RootView));
    System.gc();
}


private void unbindDrawables(View view) {

    if (view.getBackground() != null) {
        view.getBackground().setCallback(null);
    }

    if (view instanceof ViewGroup) {
        for (int i = 0; i < ((ViewGroup) view).getChildCount(); i++) {
            unbindDrawables(((ViewGroup) view).getChildAt(i));
        }

        ((ViewGroup) view).removeAllViews();
    }
}

Этот метод unbindDrawables() рекурсивно исследует дерево представления и:

  1. Удаляет обратные вызовы для всех фоновых рисунков.
  2. Удаляет дочерние элементы в каждой группе просмотра
person hp.android    schedule 21.07.2011
comment
Хорошее решение распространенной проблемы. - person While-E; 08.08.2011
comment
Это не работает для подклассов AdapterView (ListView, GridView и т. д.). - person Arjun; 19.11.2011
comment
@Arjun Да .. это не работает для подклассов AdapterView. Для этого вам нужно обработать исключение. Остальное работает нормально. Это то, что я использую в своем коде, и он отлично работает. Надеюсь это поможет. - person hp.android; 21.11.2011
comment
@hp.android Обрабатывая это в исключении, у вас есть пример того, как это будет выглядеть? Я спрашиваю, потому что у меня есть страницы изображений в моем PageAdapter, и я работаю над этой ошибкой :( - person Jacksonkr; 02.05.2012
comment
@Jackson просто измените условие: если (просмотреть экземпляр ViewGroup && !(просмотреть экземпляр AdapterView)) это избавит от исключения, которое вы получаете для адаптера - person hp.android; 08.05.2012
comment
хорошее решение, за исключением большого просмотра, оно может сильно отставать. :( - person 3c71; 03.07.2012
comment
@hp.android Я загружаю большинство своих тяжелых растровых изображений из AdaptorView. Эффективно ли это при использовании условия обработки исключений сверху? - person Siddharth Menon; 27.01.2013
comment
Я обнаружил, что это не работает на устройстве GingerBread и макете, который использует элементы ImageView. Ответ от @darrenp ниже работает лучше. - person Andrew; 15.08.2014
comment
как все заметили, он не будет работать в адаптере. Я написал этот код, но получил ошибку UnsupportedOperationException: removeAllViews() не поддерживается в AdapterView - person Bhavin Chauhan; 17.01.2015
comment
Итак, у меня есть пользователь, который постоянно переключается между действиями, то есть он может переключать 15 действий за 20 секунд. Может ли это быть причиной ошибки нехватки памяти? Что мне делать, чтобы это исправить? Спасибо! - person Ruchir Baronia; 05.01.2016

Получите анализатор памяти Eclipse ( http://www.eclipse.org/mat/) Проверьте http://kohlerm.blogspot.com/2010/02/android-memory-usage-analysis-slides.html и http://kohlerm.blogspot.com/search/label/memory

person kohlerm    schedule 20.04.2010

В основном для путешественников Google из будущего:

Большинство java-инструментов, к сожалению, не подходят для этой задачи, потому что они анализируют только JVM-Heap. Каждое Android-приложение также имеет собственную кучу, которая также должна умещаться в пределах ~ 16 МБ. Например, он обычно используется для растровых данных. Таким образом, вы можете довольно легко столкнуться с ошибками Out Of Memory, даже если ваша JVM-Heap занимает около 3 МБ, если вы используете много рисунков.

person Timo Ohr    schedule 09.05.2011
comment
начальные чертежи Android 3.0 (соты) хранятся в куче - person Gu1234; 13.09.2011
comment
@Timo, тогда что бы вы использовали для обнаружения утечек в собственной куче? - person sydd; 05.12.2011
comment
Тестирование, много тестов. Проблема в том, что вы даже не можете точно сказать, сколько памяти использует ваше приложение из-за разделения памяти и других методов оптимизации. Вы можете получить показания памяти, используя обычные команды оболочки, но это очень и очень грубые оценки. - person Timo Ohr; 06.12.2011

Ответ от @hp.android хорошо работает, если вы просто работаете с растровыми фонами, но в моем случае у меня был BaseAdapter, предоставляющий набор ImageView для GridView. Я изменил метод unbindDrawables() в соответствии с рекомендациями, чтобы условие было следующим:

if (view instanceof ViewGroup && !(view instanceof AdapterView)) {
  ...
}

но проблема в том, что рекурсивный метод никогда не обрабатывает дочерние элементы AdapterView. Чтобы решить эту проблему, я вместо этого сделал следующее:

if (view instanceof ViewGroup) {
  ViewGroup viewGroup = (ViewGroup) view;
  for (int i = 0; i < viewGroup.getChildCount(); i++)
    unbindDrawables(viewGroup.getChildAt(i));

  if (!(view instanceof AdapterView))
    viewGroup.removeAllViews();
}

так что дочерние элементы AdapterView все еще обрабатываются - метод просто не пытается удалить все дочерние элементы (что не поддерживается).

Однако это не совсем решает проблему, поскольку ImageView управляют растровым изображением, которое не является их фоном. Поэтому я добавил следующее. Это не идеально, но работает:

if (view instanceof ImageView) {
  ImageView imageView = (ImageView) view;
  imageView.setImageBitmap(null);
}

В целом метод unbindDrawables() тогда:

private void unbindDrawables(View view) {
  if (view.getBackground() != null)
    view.getBackground().setCallback(null);

  if (view instanceof ImageView) {
    ImageView imageView = (ImageView) view;
    imageView.setImageBitmap(null);
  } else if (view instanceof ViewGroup) {
    ViewGroup viewGroup = (ViewGroup) view;
    for (int i = 0; i < viewGroup.getChildCount(); i++)
    unbindDrawables(viewGroup.getChildAt(i));

    if (!(view instanceof AdapterView))
      viewGroup.removeAllViews();
  }
}

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

person darrenp    schedule 29.08.2013

Хороший доклад Google I/O (2011 г.) об управлении памятью в Android, а также подробная информация об инструментах и ​​методах профилирования памяти:
http://www.youtube.com/watch?v=_CruQY55HOk

person greg7gkb    schedule 16.04.2012
comment
Или соответствующую запись в блоге: android-developers.blogspot. ком/2011/03/ - person greg7gkb; 17.04.2012
comment
Итак, у меня есть пользователь, который постоянно переключается между действиями, то есть он может переключать 15 действий за 20 секунд. Может ли это быть причиной ошибки нехватки памяти? Что мне делать, чтобы это исправить? Спасибо!' - person Ruchir Baronia; 05.01.2016

Valgrind был портирован на Android (при поддержке Mozilla). См. Valgrind для Android — Текущее состояние и Поддержка запуска Valgrind для Android на ARM (комментарий 67).

person jww    schedule 19.10.2011
comment
это потребует создания пользовательского рома. - person Akshat; 16.06.2012

Что ж, это инструменты, которые связываются с уникальными форматами, которые использует Android.

Пробовали ли вы имитировать тестирование областей кода с помощью Android Mock Framework?

person Fred Grott    schedule 18.07.2009
comment
не так много, тестирование такого рода - это не столько проблема, сколько запись того, что на самом деле происходит во время работы приложения, что мне действительно нужно, так это инструмент профилирования утечки ресурсов/памяти - person jottos; 20.07.2009