Почему этот Activity всё равно течёт после поворота, несмотря на WeakReference?
После поворота экрана старый Activity так и не собирается, хотя Job держит его через WeakReference. Объясните утечку и исправьте её, не ограничиваясь удалением WeakReference.
class MainActivity : AppCompatActivity() {
inner class Job(private val ref: WeakReference<MainActivity>) {
fun run() = Thread { /* работа с ref.get() */ }.start()
}
fun doJob() = Job(WeakReference(this)).run()
}
Определите причину и исправьте.
inner class держит неявную сильную ссылку на внешний MainActivity (this$0), а работающий Thread удерживает Job, — поэтому старый Activity остаётся достижим, а WeakReference тут отвлекающий манёвр. Решение — сделать Job nested (не inner) классом.
- ✗Винить
WeakReferenceвместо неявной ссылкиinner-класса на внешний объект - ✗Думать, что
innerне несёт ссылки на свой внешний класс - ✗Переходить на
SoftReferenceвместо разрыва сильной внешней связи
- →В чём разница между
inner classиnested-классом в Kotlin? - →Почему долгоживущий
Threadдействует как GC-корень для всего, что держит?
Баг
В Kotlin inner class хранит неявную сильную ссылку на экземпляр внешнего класса (MainActivity.this, в байткоде this$0). Запущенный Thread удерживает Job, а Job (как inner) удерживает старый MainActivity. После поворота экрана создаётся новый Activity, но старый остаётся достижимым через цепочку Thread → Job → MainActivity → утечка.
class MainActivity : AppCompatActivity() {
inner class Job(private val ref: WeakReference<MainActivity>) { // ❌ inner
fun run() = Thread { /* ... */ }.start() // поток держит Job → Activity
}
}
WeakReference внутри — отвлекающий манёвр: неявная ссылка от inner сильная и обходит её.
Исправление
Сделайте Job обычным nested-классом (уберите inner). Тогда у него нет ссылки this$0, и доступ к Activity идёт только через WeakReference, которую GC может освободить.
class MainActivity : AppCompatActivity() {
class Job(private val ref: WeakReference<MainActivity>) { // ✅ nested
fun run() = Thread { /* ref.get()?.let { ... } */ }.start()
}
}