Извлечение NsdManager всегда приводит к утечке активности

#android #android-context #nsd #nsdmanager

#Android #android-контекст #nsd #nsdmanager

Вопрос:

При профилировании моего приложения я обнаружил, что извлечение NsdManager с помощью

 nsdManager = (NsdManager) getSystemService(Context.NSD_SERVICE);  // LEAKS!
  

происходит утечка активности, в то время как

 nsdManager = (NsdManager) getApplicationContext().getSystemService(Context.NSD_SERVICE);
  

нет. Я создал небольшое тестовое приложение, которое ничего не делает с
NsdManager, кроме как извлекает его с помощью контекста Activity,
но оно все еще пропускает activity. Это ошибка? Действительно
ли мне нужно постоянно использовать контекст приложения?

Устройство: Эмулятор (Android 11, API 30, x86)

Комментарии:

1. Как вы определяете, что происходит утечка? Что это утечка? Вы видите утечку в более старых версиях Android?

2. GitHub: github.com/roplacebo/NsdManager.git . Нажмите кнопку, чтобы перейти к NsdActivity, где NsdManager извлекается из контекста действия. Затем вернитесь назад. Дампы кучи с утечкой Canary и профилировщиком памяти. То же самое с Samsung Galaxy Tab S2 (Nougat)

3. Хорошо, я могу воспроизвести проблему с вашим проектом. Я не уверен, насколько «реальна» утечка. Что-то глубоко в внутренностях Android содержит AsyncChannel ссылку на вашу активность, и я не знаю, будет ли / когда эта ссылка будет выпущена. Вы можете подумать о том, чтобы следовать инструкциям этой записи часто задаваемых вопросов, чтобы попытаться определить, относится ли это к LeakCanary как «утечка библиотеки» или нет.

4. Спасибо, что изучили это! Я подал ошибку здесь: issuetracker.google.com/issues/173689855

Ответ №1:

Эта проблема похожа на проблемы с утечкой памяти при получении WIFI_SERVICE.

При выполнении:

 activity.getSystemService(Context.WIFI_SERVICE);
  

Android Studio lint показывает следующее предупреждение.

 The WIFI_SERVICE must be looked up on the 
Application context or memory will leak on
devices < Android N. Try changing activity
to activity.getApplicationContext().
  

Хотя в NSD_SERVICE нет предупреждения об утечке и потому, что я вижу утечки памяти, ссылающиеся на NsdManager при использовании:

 activity.getSystemService(Context.NSD_SERVICE);
  

Я думаю, что с помощью:

 activity.getApplicationContext().getSystemService(Context.NSD_SERVICE);
  

похоже, правильное действие.