Как использовать утечку канарейки
Я знаю, что это, наверное, немой вопрос, но я довольно новичок в разработке Android, и в настоящее время я испытываю OutOfMemoryError в своих приложениях, которые я пытался отлаживать с помощью MAT, но все равно слишком сложно найти утечку в нескольких действиях, тогда я нашел LeakCanary, который кажется более простым и простым в использовании, однако я не мог найти начального пошагового руководства по использованию Leak Canary даже в Google. Я установил LeakCanary через зависимости в моей build.gradle, и это то, что я получил до сих пор:
ExampleApplication.java
public class ExampleApplication extends Application {
public static RefWatcher getRefWatcher(Context context) {
ExampleApplication application = (ExampleApplication) context.getApplicationContext();
return application.refWatcher;
}
private RefWatcher refWatcher;
@Override
public void onCreate() {
super.onCreate();
refWatcher = LeakCanary.install(this);
}
final class KeyedWeakReference extends WeakReference<Object> {
public final String key;
public final String name;
KeyedWeakReference(Object referent, String key, String name,
ReferenceQueue<Object> referenceQueue) {
super(checkNotNull(referent, "referent"), checkNotNull(referenceQueue, "referenceQueue"));
this.key = checkNotNull(key, "key");
this.name = checkNotNull(name, "name");
}
}
public void watch(Object watchedReference, String referenceName) {
checkNotNull(watchedReference, "watchReference");
checkNotNull(referenceName, "referenceName");
if(debuggerControl.isDebuggerAttached()) {
return;
}
final long watchStartNanoTime = System.nanoTime();
String key = UUID.randomUUID().toString();
retainedKeys.add(key);
final KeyedWeakReference reference =
new KeyedWeakReference(watchedReference, key, referenceName, queue);
watchExecutor.execute()
}
}
Скажем, у меня есть Activity, где я хочу, чтобы LeakCanary просматривал объект
SampleActivity.java
public class SampleActivity extends Activity implements View.OnClickListener {
ImageView level001, level002;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.choose_level);
level001 = (ImageView) findViewById(R.id.level001);
level002 = (ImageView) findViewById(R.id.level002);
// Do all kinds of function
// How do I use LeakCanary to watch these objects ?
}
}
Теперь, как я могу использовать LeakCanary, чтобы увидеть, какой объект вызывает утечку памяти. Благодарим вас за помощь и помощь.
Ответы
Ответ 1
Хорошая вещь о канале утечки - как автоматизировано это работает.
По умолчанию он уже "наблюдает" за действиями, которые не соответствуют GCed. Поэтому из коробки, если какая-либо активность протекает, вы должны получить уведомление.
В моем проекте я добавил дополнительный метод для Application
следующим образом:
public class ExampleApplication extends Application {
public static ExampleApplication instance;
private RefWatcher refWatcher;
@Override
public void onCreate() {
super.onCreate();
instance = this;
refWatcher = LeakCanary.install(this);
}
public void mustDie(Object object) {
if (refWatcher != null) {
refWatcher.watch(object);
}
}
}
поэтому важный материал с сборкой мусора и утечкой памяти и канарейкой должен знать, когда собирать материал и просить, чтобы этот элемент просматривался.
Например, мы используем "базовый фрагмент" со следующим кодом:
@Override
public void onDestroy() {
super.onDestroy();
ExampleApplication.instance.mustDie(this);
}
таким образом LeakCanary
пытается проверить, не протекает ли какой-либо фрагмент памяти.
Итак, для дальнейшего внедрения в вашем приложении вы можете/должны выполнять задачи или экземпляры, которые, как вы знаете, должны собирать мусор, но вы думаете, что это может быть не так, и вы не знаете, где вы можете это назвать: ExampleApplication.instance.mustDie(object);
а затем вы ДОЛЖНЫ запускать приложение и поворачивать устройство и вызывать утечку, поэтому утечка canary может захватить/проанализировать трассировку стека и дать вам ценную информацию о том, как ее исправить.
Надеюсь, это поможет.
Ответ 2
Я использовал здесь в приложении
import android.content.Context;
import android.support.multidex.MultiDex;
import android.support.multidex.MultiDexApplication;
import com.squareup.leakcanary.LeakCanary;
import com.squareup.leakcanary.RefWatcher;
import school.my.com.school.BuildConfig;
public class AppController extends MultiDexApplication {
private RefWatcher refWatcher;
public static RefWatcher getRefWatcher(Context context) {
AppController application = (AppController) context.getApplicationContext();
return application.refWatcher;
}
@Override
public void onCreate() {
super.onCreate();
if(BuildConfig.DEBUG)
refWatcher = LeakCanary.install(this);
}
}
Вы можете использовать здесь Приложение вместо MultiDexApplication
Ответ 3
У меня был тот же вопрос о том, как использовать LeakCanary. Я просто хотел увидеть базовый пример того, как его запустить, и увидеть мой первый путь к утечке объекта.
Как использовать LeakCanary
Вот основной пример того, как работает LeakCanary:
Как использовать LeakCanary (4 минуты 13 секунд)
Одна из проблем, которую мне пришлось преодолеть, заключалась в том, чтобы выяснить, что мне нужно запускать приложение в обычном режиме запуска, а не в режиме отладки. Мне также пришлось отклониться от основных инструкций и установить файл build.gradle
уровня build.gradle
следующим образом:
dependencies {
debugImplementation 'com.squareup.leakcanary:leakcanary-android:1.5.4'
releaseImplementation 'com.squareup.leakcanary:leakcanary-android:1.5.4'
}
Я думаю, что debugImplementation
не работал для меня, потому что LeakCanary игнорирует обнаружение утечек при отладке. Хотя LeakCanary заявляет, что предоставляет версию "no-op" своей библиотеки для выпуска, так как отладка у меня не сработала, я изменил releaseImplementation
выше с рекомендуемого com.squareup.leakcanary:leakcanary-android-no-op:1.5.4
в com.squareup.leakcanary:leakcanary-android:1.5.4
.
Как вы можете видеть на видео, еще одна проблема, с которой мне приходилось сталкиваться, заключалась в предоставлении доступа на запись в LeakCanary. Я провела пальцем вниз и увидела уведомление от LeakCanary о том, что не удалось получить доступ для записи (подробнее). Я никогда не видел запрос на разрешение. Таким образом, в одном случае (не показанном на видео) я дал своему приложению доступ на запись, перейдя в приложение "Настройки", найдя мое приложение (в отличие от приложения под названием "Leak", которое устанавливает LeakCanary) и включив доступ для записи. В видео мне не нужно было этого делать, потому что я дал разрешение, ответив на уведомление. Затем во время использования моего приложения я периодически проверяю наличие новых уведомлений (проводя вниз). Я видел сообщения типа "Утечка XYZActivity 217 КБ". Я нажал на это, и это заняло меня в этом приложении Leak.
Кроме того, я заметил, что иногда анализ может занять до нескольких минут и отображать уведомление об утечке памяти на вашем телефоне.
Как проверить исправление утечки памяти с помощью LeakCanary
Теперь, когда я исправил некоторые утечки памяти, я использую LeakCanary для проверки исправления. Однако, если LeakCanary ничего не сообщает, я не обязательно верю в это, потому что моя утечка исправлена. Это может быть просто LeakCanary сломан.
Как проверить исправление утечки памяти с помощью LeakCanary (16 минут 34 секунды)
Процесс проверки утечки памяти с помощью LeakCanary: 1. Подтвердите утечку памяти с помощью LeakCanary 2. Исправьте утечку памяти и подтвердите, что LeakCanary сообщает об отсутствии утечек 3. Отмените исправление и подтвердите, что LeakCanary снова сообщает об утечке
Поскольку LeakCanary показывает очень мало информации о состоянии, когда он работает, трудно понять, что он вообще делает. Это привело меня к мысли, что я исправил утечку памяти, а на самом деле я этого не сделал. Три шага, описанные выше, являются лучшим способом проверки утечки памяти с помощью LeakCanary.
Ответ 4
Я использовал Leak-Canary, как показано ниже:
1) Зависимость Gradle:
debugImplementation 'com.squareup.leakcanary:leakcanary-android:1.4'
2) Класс применения:
@Override
public void onCreate() {
super.onCreate();
if (BuildConfig.DEBUG) {
StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder()
.detectCustomSlowCalls()
.detectNetwork()
.penaltyLog()
.penaltyDeath()
.build());
StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder()
.detectActivityLeaks()
.detectLeakedClosableObjects()
.detectLeakedRegistrationObjects()
.detectLeakedSqlLiteObjects()
.penaltyLog()
.penaltyDeath()
.build());
LeakLoggerService.setupLeakCanary(this);
}
}
3) Класс LeakLoggerService: поместите этот класс в пакет отладки, созданный gradle.
public class LeakLoggerService extends DisplayLeakService {
public static void setupLeakCanary(Application application) {
if (LeakCanary.isInAnalyzerProcess(application)) {
// This process is dedicated to LeakCanary for heap analysis.
// You should not init your app in this process.
return;
}
LeakCanary.install(application, LeakLoggerService.class,
AndroidExcludedRefs.createAppDefaults().build());
}
@Override
protected void afterDefaultHandling(HeapDump heapDump, AnalysisResult result, String leakInfo) {
if (!result.leakFound || result.excludedLeak) {
return;
}
Log.w("LeakCanary", leakInfo);
}
4) Зарегистрировать сервис для манифеста файла и 1 разрешение:
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<service android:name=".LeakLoggerService" />
5) Наконец, проверьте, если установка прошла успешно: утечка активности;)
public class Main2Activity extends AppCompatActivity {
static TextView label;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
label = new TextView(this);
label.setText("asds");
setContentView(label);
if (ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(this,new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE},
}
}
убить это действие и проверить журналы с тегом: LeakCanary
Он должен работать...