Какие инструменты и методы Android лучше всего подходят для поиска утечек памяти/ресурсов?
У меня появилось приложение для Android, и я нахожусь в разработке приложений для телефона, где все, кажется, работает хорошо, и вы хотите объявить победу и отправить, но вы знаете, что просто нужно быть какой-то памятью и утечки ресурсов там; и там всего 16 мб кучи на Android и, по-видимому, удивительно легко утечка в приложении для Android.
Я смотрел вокруг и до сих пор мог только выкопать информацию о 'hprof' и 'traceview', и не получил много положительных отзывов.
Какие инструменты или методы вы столкнулись или разработали и можете поделить, возможно, в проекте ОС?
Ответы
Ответ 1
Одной из наиболее распространенных ошибок, которые я обнаружил при разработке приложений для Android, является ошибка "java.lang.OutOfMemoryError: Bitmap Size Exceeds VM Budget". Я быстро обнаружил эту ошибку при работе с большим количеством растровых изображений после изменения ориентации: активность уничтожена, снова создана, а макеты "завышены" из XML, потребляющего память VM, доступную для растровых изображений.
Растровые изображения в предыдущем макете деятельности не были должным образом освобождены сборщиком мусора, поскольку они пересекли ссылки на их активность. После многих экспериментов я нашел неплохое решение этой проблемы.
Сначала установите атрибут "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() вашей операции вызовите метод unbindDrawables(), передающий подтверждение родительскому представлению, а затем выполните команду 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() исследует дерево представления рекурсивно и:
- Удаляет обратные вызовы во всех фоновых рисунках
- Удаляет дочерние элементы во всех группах просмотра
Ответ 2
Получить анализатор памяти 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
Ответ 3
В основном для путешественников Google в будущем:
Большинство java-инструментов, к сожалению, не подходят для этой задачи, потому что они анализируют только JVM-кучу. Однако у каждого приложения Android также есть своя куча, которая также должна соответствовать пределу ~ 16 МБ. Например, он обычно используется для растровых данных. Таким образом, вы можете легко запускать ошибки Out Of Memory, даже если ваша JVM-куча - chillin около 3 МБ, если вы используете множество чертежей.
Ответ 4
Ответ от @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();
}
}
Я надеюсь, что существует более принципиальный подход к освобождению таких ресурсов.
Ответ 5
Хорошие разговоры о вводе/выводе Google (2011) по управлению памятью в Android, а также подробные сведения о инструментах + методы для профилирования памяти:
http://www.youtube.com/watch?v=_CruQY55HOk
Ответ 6
Valgrind портирован на Android (спонсируется Mozilla). См. Valgrind на Android - текущий статус и Поддержка запуска Valgrind для Android на ARM (комментарий 67).
Ответ 7
Ну, это те инструменты, которые связаны с уникальными форматами, которые использует Android. Я думаю, что вы можете быть неудовлетворены тем, что используется базовая структура кода тестирования.
Вы пробовали тестировать области кода с помощью Android Mock Framework?