Утечка памяти Android LocationManager

Я получил экземпляр LocationManager с помощью getSystemSercice (LOCATION_SERVICE) активности. Через несколько минут утечка канарейки обнаруживает утечку памяти:

┬───
│ GC Root: Global variable in native code
│
├─ android.location.LocationManager$ListenerTransport instance
│    Leaking: UNKNOWN
│    ↓ LocationManager$ListenerTransport.this$0
│                                        ~~~~~~
├─ android.location.LocationManager instance
│    Leaking: UNKNOWN
│    ↓ LocationManager.mContext
│                      ~~~~~~~~
├─ android.app.ContextImpl instance
│    Leaking: UNKNOWN
│    ↓ ContextImpl.mAutofillClient
│                  ~~~~~~~~~~~~~~~
╰→ com....manager.MapsActivity instance
​     Leaking: YES (ObjectWatcher was watching this because com...manager.live2.MapsActivity received Activity#onDestroy() callback and Activity#mDestroyed is true)
​     key = 3e8186a7-b057-4c0a-aca2-b0fc4257bb11
​     watchDurationMillis = 107841
​     retainedDurationMillis = 102829

METADATA

Build.VERSION.SDK_INT: 29
Build.MANUFACTURER: Xiaomi
LeakCanary version: 2.3
App process name: com...
Analysis duration: 9763 ms```

person user6915871    schedule 24.06.2020    source источник
comment
попробуйте locationManager.removeUpdates(this); когда вам не нужен locationManager   -  person S T    schedule 24.06.2020
comment
@user6915871 user6915871 вы можете подтвердить, что вызывали removeUpdates? Можете ли вы поделиться кодом активности?   -  person Pierre-Yves Ricau    schedule 18.07.2020


Ответы (1)


Мой предыдущий ответ был неверным, так как я предполагал, что у ContextImpl другой жизненный цикл, чем у действия, которое имеет его в качестве базового контекста. Оказывается, у них одинаковый жизненный цикл (прокомментируйте здесь: https://issuetracker.google.com/issues/159308651#comment6)

Что это означает для этой конкретной проблемы, так это то, что утечка находится в другом месте. Чтение источника и трассировки утечки:

  • LocationManager имеет поле mContext, указывающее на ContextImpl, который ссылается на действие. Это означает, что жизненный цикл LocationManager должен быть таким же, как и у активности.
  • Однако он хранится в памяти с помощью LocationManager$ListenerTransport, который является связующим звеном, хранящимся в собственной памяти, и используется для того, чтобы другой процесс мог вернуться к этому процессу. Пока другой процесс не отпустит ссылку на связующее на своей стороне, связующее не может быть проверено на стороне приложения. Это классическая утечка AOSP, и исправление должно быть либо для LocationManager в контексте приложения, либо для LocationManager$ListenerTransport, чтобы отпустить его ссылку на его внешний класс (т.е. сделать его статическим классом с нулевой ссылкой), когда активность уничтожен.

Это все в AOSP, хотя. Можете ли вы в своем приложении вызвать getSystemSercice(LOCATION_SERVICE) в контексте приложения, а не в контексте активности? т.е. в вашей деятельности вместо this.getSystemSercice(LOCATION_SERVICE); попробуйте this.getApplication().getSystemSercice(LOCATION_SERVICE);.

Изменить: или может быть код активности не вызывает locationManager.removeUpdates(this);

person Pierre-Yves Ricau    schedule 17.07.2020
comment
getApplicationContext() это решение. Спасибо - person anatoli; 27.05.2021