Как разработчик Android, я много раз слышал, что View (Activity/Fragments) не должен содержать никаких ссылок на объекты с более длинным жизненным циклом (например, Application), иначе GC не сможет собрать его и произойдет утечка памяти.
Но сегодня я попытался воспроизвести эту проблему и получил неожиданный результат - GC по-прежнему собирает Activity, даже если она имеет ссылку на класс Application.
Я запустил его на 3 устройствах (API: 22,24,28) и получил тот же результат.
Вот код, который я использовал для теста:
Посмотреть:
class MainActivity : AppCompatActivity() {
var gcBlocker = ApplicationContext.inst.list
override fun onCreate(savedInstanceState: Bundle?) {
Log.d("custom_masher", "CREATE!")
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
gcBlocker.forEach {
Log.d("app", it.toString())
}
}
fun finalize(){
Log.d("custom_masher", "FINALIZE!")
}
}
Заявка:
class ApplicationContext : Application() {
var list = listOf<Int>(1, 2, 3)
companion object {
lateinit var inst:ApplicationContext
}
override fun onCreate() {
super.onCreate()
inst = this
}
}
Как я это воспроизвожу:
Включите "Не сохранять действия" в параметрах разработчика на устройстве Android, чтобы принудительно убить активность
Скомпилируйте код выше
Закройте (сверните) приложение и откройте его снова несколько раз. MainActivity.onCreate запускается каждый раз, когда я закрываю/открываю Activity
Закрыть (свернуть) приложение
-x-> через 10-30 секунд я получил журнал, что все созданные действия были завершены (сборка мусора)
---> созданные действия не должны собираться мусором, поскольку они содержат ссылку на класс Application
У кого-нибудь есть идеи, почему это происходит? Значит ли это, что нам вообще не нужно беспокоиться об утечках активности? :)
PS Я также сделал ту же проблему без опции "Не держать деятельность"
Окей, я понял это, когда вспомнил основные термины GC :)
GC собирает объект, когда корневой объект (приложение) не может обогатить собранный объект.
В моем случае, хотя MainActivity имеет ссылку на экземпляр приложения, экземпляр приложения по-прежнему не может обогащать какой-либо метод или свойство MainActivity, поэтому, когда Android освобождает действие, оно собирается GC.
Если я передал ссылку Activity или обратный вызов в класс Application, то MainActivity не будет собираться GC.