На самом деле, данная статья является продолжением данного топика: Анализ памяти для Android приложений. Всем, кто хочет изучить вопрос детально, будут рады под катом.
Анализировать состояние памяти с помощью инструментов, описанных в данной статье, вещь очень нужная и полезная, но не всегда это делать удобно и уместно.
Было бы неплохо, иметь возможность отслеживать memory leaks без каких-либо сторонних инструментов, чтобы даже неопытный тестер смог отыскать утечки памяти без доступа к компьютеру.
На помощь нам придет особенность класса WeakReference.
Ниже приведен пример класса, который будет помогать отслеживать утечки памяти. На оригинальность данный класс не претендует, и, возможно, кто-то уже даже использует в своем проекте что-то подобное. Класс по понятным причинам был упрощен и слегка модифицирован, но свою основную функцию он выполняет. Скажу лишь, что для большего удобства, в результирующий список можно добавить как минимум количество «утекших» объектов.
Для начала придется написать простую Activity, которая будет брать и отображать список строчек возвращаемый функцией
Далее, каждый объект, который необходимо отслеживать, мы добавляем в LeaksManager следующим образом:
Далее, в удобном для вас месте, вы размещаете вызов Activity со списком memory leaks, и, если список пустой, то все хорошо, а если в нем что-то осталось даже после нескольких запусков этой самой Activity, то есть повод задуматься.
В общем-то, это все, что нужно сделать.
Отслеживать все создаваемые объекты нет никакого смысла — большинство объектов привязаны к контексту, и поэтому для них вполне достаточно вызывать monitorObject() в onCreate() каждой Activity, сервиса ну и возможно в конструкторе потока.
Данный класс ни в коем случае не избавляет от необходимости использования инструментов, описанных в данной статье, но достаточно облегчает контроль утечек памяти как разработчикам, так и тестерам. На проекте, где я участвую, перед каждым не тривиальным сабмитом принято делать такой «быстрый» тест на утечки памяти — времени занимает мало и позволяет сразу же обнаружить проблемы, не позволяя им выявлять себя перед сдачей релиза.
Надеюсь эта статья будет кому-нибудь полезна.
Если данная статья будет интересна, то в следующей статье я поведаю о хитрой особенности класса AsyncTask
Итак, поехали...
Анализировать состояние памяти с помощью инструментов, описанных в данной статье, вещь очень нужная и полезная, но не всегда это делать удобно и уместно.
Было бы неплохо, иметь возможность отслеживать memory leaks без каких-либо сторонних инструментов, чтобы даже неопытный тестер смог отыскать утечки памяти без доступа к компьютеру.
Как это сделать
На помощь нам придет особенность класса WeakReference.
Ниже приведен пример класса, который будет помогать отслеживать утечки памяти. На оригинальность данный класс не претендует, и, возможно, кто-то уже даже использует в своем проекте что-то подобное. Класс по понятным причинам был упрощен и слегка модифицирован, но свою основную функцию он выполняет. Скажу лишь, что для большего удобства, в результирующий список можно добавить как минимум количество «утекших» объектов.
package com.company.product;
import java.lang.ref.WeakReference;
import java.util.Collections;
import java.util.Vector;
import android.content.Context;
import android.content.Intent;
import android.text.TextUtils;
public class LeaksManager {
private static LeaksManager mThis = null;
private final Vector<WeakReference<Object>> mRefs = new Vector<WeakReference<Object>>();
private LeaksManager() {
super();
}
public static LeaksManager getThis() {
if (mThis == null) {
mThis = new LeaksManager();
}
return mThis;
}
public <T> T monitorObject(T obj) {
if (obj == null) {
return obj;
}
for (WeakReference<Object> ref : mRefs) {
if (ref.get() == obj) {
return obj;
}
}
mRefs.add(new WeakReference<Object>(obj));
return obj;
}
public Vector<String> checkLeaks() {
System.gc();
Vector<String> names = new Vector<String>();
for (int i = mRefs.size() - 1; i >= 0; i--) {
WeakReference<Object> ref = mRefs.elementAt(i);
Object obj = ref.get();
if (obj != null) {
String className = obj.getClass().getSimpleName();
addUniqueClassName(names, TextUtils.isEmpty(className) ? "Unknown class name" : className);
}
else {
mRefs.remove(i);
}
}
mRefs.trimToSize();
return names;
}
private void addUniqueClassName(Vector<String> names, String className) {
int index = -1;
for (int j = 0; j < names.size(); j++) {
if (names.elementAt(j).equals(className)) {
index = j;
break;
}
}
if (index == -1) {
names.add(names.getClass().getSimpleName());
}
}
}
Как этим пользоваться
Для начала придется написать простую Activity, которая будет брать и отображать список строчек возвращаемый функцией
LeaksManager.checkLeaks()
. Данная Activity очень простая, поэтому не вижу большого смысла приводить ее код.Далее, каждый объект, который необходимо отслеживать, мы добавляем в LeaksManager следующим образом:
Object obj = LeaksManager.getThis().monitorObject(new Object());
Далее, в удобном для вас месте, вы размещаете вызов Activity со списком memory leaks, и, если список пустой, то все хорошо, а если в нем что-то осталось даже после нескольких запусков этой самой Activity, то есть повод задуматься.
В общем-то, это все, что нужно сделать.
Комментарии
Отслеживать все создаваемые объекты нет никакого смысла — большинство объектов привязаны к контексту, и поэтому для них вполне достаточно вызывать monitorObject() в onCreate() каждой Activity, сервиса ну и возможно в конструкторе потока.
Данный класс ни в коем случае не избавляет от необходимости использования инструментов, описанных в данной статье, но достаточно облегчает контроль утечек памяти как разработчикам, так и тестерам. На проекте, где я участвую, перед каждым не тривиальным сабмитом принято делать такой «быстрый» тест на утечки памяти — времени занимает мало и позволяет сразу же обнаружить проблемы, не позволяя им выявлять себя перед сдачей релиза.
P.S.
Надеюсь эта статья будет кому-нибудь полезна.
Если данная статья будет интересна, то в следующей статье я поведаю о хитрой особенности класса AsyncTask