Xotira oqishi — mobil ishlanmadagi eng makkor muammolardan biridir. Ilova xotiri doimiy ravishda o'sib boradi, toki operatsion tizim tomonidan belgilangan chegaraga yetguncha, shundan so'ng OutOfMemoryError yoki majburiy tugatish yuz beradi. Square Engineering ma'lumotlariga ko'ra, taxminan 40% Android ilovalarida faqat profillash vaqtida aniqlanishi mumkin bo'lgan kamida bitta xotira oqishi mavjud. Xotira o'sishining sabablari va oldini olish usullarini ko'rib chiqamiz.
Asosiy fikrlar
Xotira oqishi (memory leak) — ilovaga endi kerak bo'lmagan ob'ektning, ildiz to'plamidan (GC Root) faol havola mavjudligi sababli xotirada qolishda davom etishi. Axlat yig'uvchi bunday ob'ektni tirik deb hisoblaydi va uni o'chirmaydi.
Xotira shishishi (memory bloat) — ilova joriy vazifalarni bajarish uchun zarur bo'lganidan ko'ra ko'proq xotira iste'mol qiladigan kengroq muammo. Sabablari: haddan tashqari keshlash, ob'ektlarning takrorlanishi, optimal bo'lmagan ma'lumot tuzilmalari va xotira parchalanishi.
Android ilovalari uchun cheklangan xotira ajratiladi (odatda qurilma va OT versiyasiga qarab 64-512 MB). iOS chegarasi kamroq qattiq, ammo tizim chegaraga yaqinlashganda xotira ogohlantirishini yuboradi.
| Xususiyat | Android | iOS |
|---|---|---|
| Xotira chegarasi | 64-512 MB (qurilmaga bog'liq) | Yashirin (tizim) |
| Axlat yig'ilishi | ART (Concurrent, Compact) | ARC (Automatic Reference Counting) |
| Oqish mexanizmi | GC Root havolalari | Retain cycles (kuchli havola sikllari) |
| Natija | OutOfMemoryError | Xotira ogohlantirishi → tugatish |
Facebook Engineering Blog ma'lumotlariga ko'ra, xotira oqishlari mobil ilovalardagi crash hisobotlarining ~15% sababidir. Android-da bunga xotira yetishmasligida tez-tez GC pauzalari sababli ANR qo'shiladi.
Activity-ga statik havola — Android oqishlarining klassikasi. Statik maydon yoki singleton Activity-ga havola saqlasa, singleton tirik ekan, finish() dan keyin ham GC tomonidan yig'ilmaydi. Activity View hierarchy, resurslar va Context-ni o'z ichiga olgan og'ir ob'ektdir.
object LeakHolder {
var activityRef: Activity ?= null // oqish: Activity ga statik havola
}
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle ?= null) {
super.onCreate(savedInstanceState)
LeakHolder.activityRef = this // ❌ MainActivity hech qachon GC tomonidan yig'ilmaydi
}
}
Anonim sinflar va lambdalar — yashirincha tashqi sinfga havola saqlaydi. Agar Runnable yoki Callback tashqi xizmatga uzatilsa va Activity yo'q qilinsa, anonim sinf ob'ekti hali ham navbatda qoladi va Activity ning axlat yig'ilishiga ketishiga to'sqinlik qiladi.
iOS-da asosiy muammo retain cycles: ikkita ob'ekt bir-biriga kuchli havolalar saqlaydi va ARC hech biri uchun havola sonini nolga tushirolmaydi. Oddiy hol: self ni kuchli tutadigan closure va self ning closure ga havola saqlashi.
LeakCanary — Android-da avtomatik oqish aniqlash uchun Square kutubxonasi. Activity yoki Fragment yo'q qilingandan so'ng ob'ektning GC tomonidan yig'ilgan-yig'ilmaganligini tekshiradi. Agar yo'q bo'lsa — heap dump qiladi va oqish trace-ni ko'rsatadi.
// LeakCanary 2.x — Application orqali avto-integratsiya
class ExampleApplication : Application() {
override fun onCreate() {
super.onCreate()
// LeakCanary debug qurilmasida avtomatik o'rnatiladi
// ContentProvider orqali — nol kod sozlamasi
}
}
// Majburiy tekshirish chaqiruvi
AppWatcher.objectWatcher.watch(watchedObject, "leak description")
Android Studio Profiler — real vaqtda xotirani kuzatish uchun o'rnatilgan vosita. Heap dump yozishga, shubhali ob'ektlarni (Retained Size > 1 MB) topishga va har bir ob'ektgacha GC root yo'lini kuzatishga imkon beradi.
iOS uchun Xcode Memory Graph Debugger dan foydalaning. U xotiradagi ob'ektlar grafigini vizuallashtiradi, retain cycles ni ko'rsatadi va aylanma havolalarni darhol aniqlashga imkon beradi. Uzoq muddatli kuzatish uchun Instruments > Allocations ham mavjud.
WeakReference — axlat yig'ilishiga to'sqinlik qilmasligi kerak bo'lgan havolalar uchun asosiy mexanizm. GC ob'ektni o'chirishga qaror qilsa, WeakReference null qaytaradi. Qayta chaqiruvlar, tinglovchilar va fon iplaridan UI komponentlariga havolalar uchun ishlatiladi.
Lifecycle-aware komponentlari — Android Jetpack (Lifecycle, LiveData, Flow, coroutines) da amalga oshirilgan arxitektura yondashuvi. Obunalar onDestroy da avtomatik bekor qilinadi, bu esa asosiy oqish sinfini yo'q qiladi.
class MyViewModel : ViewModel() {
private val _data = MutableLiveData<List<User>>()
val data: LiveData<List<User>> get() = _data
fun loadData() {
viewModelScope.launch {
val result = repository.fetchData()
_data.postValue(result)
// korutina onCleared() da avtomatik bekor qilinadi
}
}
}
viewModelScope va lifecycleScope — Android-da hayot aylanish hodisasi paytida bekor qilinadigan o'rnatilgan CoroutineScope-lar. Bu korutinlar orqali oqishlarni yo'q qiladi — zamonaviy Android ishlanmasidagi eng keng tarqalgan stsenariy.
Memory Profiler in Android Studio — xotirani kuzatish uchun asosiy vosita. Jonli ajratmalarni, xotira suratlarini, turlar bo'yicha ob'ektlar sonini ko'rsatadi. Dump yozishga va shubhali ob'ektlarni topish uchun MAT (Memory Analyzer Tool) da tahlil qilishga imkon beradi.
Eclipse MAT — xotira dump-lari uchun ish stoli analizatori. Android Studio dan HPROF fayli yuklangandan so'ng MAT dominator daraxtini quradi, har bir ob'ektning retain hajmini ko'rsatadi va Leak Suspects Report orqali shubhali oqishlarning avtomatik tahlilini taklif qiladi.
Xcode Memory Graph — retain cycles uchun vizual debugger. Memory Graph Debugger tugmasini bosganda Xcode ilovani to'xtatadi, xotiradagi ob'ektlarning to'liq grafigini quradi va retain cycles ni qizil rang bilan ajratib ko'rsatadi.
| Vosita | Platforma | Xususiyat |
|---|---|---|
| LeakCanary | Android | Yo'q qilishdan keyin avtomatik oqish aniqlash |
| Memory Profiler | Android Studio | Heap dump + jonli ajratmalar |
| Eclipse MAT | Android | Dominator daraxti, Leak Suspects Report |
| Memory Graph | iOS (Xcode) | Retain cycles vizuallashtiruvchisi |
Google I/O 2023 ma'lumotlariga ko'ra, debug qurilmalarida LeakCanary ishlatadigan ilovalar joriy qilingandan keyin dastlabki 2 oy ichida xotira bilan bog'liq crash-lar sonini 30-50% kamaytiradi. LeakCanary ni loyihaga onboarding bosqichida qo'shish tavsiya etiladi.
Tez-tez beriladigan savollar
Oqish — kod uchun mavjud bo'lmagan, lekin faol havolalar sababli GC tomonidan o'chirilmaydigan ob'ektlar. Shishish — ilova mantiqan kerak bo'lgan, lekin haddan tashqari miqdordagi ob'ektlarni xotirada saqlashi (masalan, 80 MB ishlaydigan ilovada 50 MB keshlash). Shishish arxitektura yo'li bilan davolanadi, oqish — havolalarni to'g'ri boshqarish orqali.
LeakCanary ObjectWatcher ishlatadi — onDestroy() Activity dan keyin Activity ga WeakReference yaratadi va GC ni ishga tushiradi. Agar 5 soniyadan keyin WeakReference tozalanmasa, LeakCanary heap dump qiladi, GC Root dan ob'ektgacha eng qisqa havola zanjirini tahlil qiladi va fayl nomi va kod qatori bilan aniq oqish stekini ko'rsatadi.
Bitmap Java xotirasidan tashqarida, native xotirada (native heap) joy egallaydi. Bitta Bitmap ning hajmi = en × balandlik × 4 bayt (ARGB_8888). 12 MP foto (4000×3000) 48 MB egallaydi. Android har doim ham native xotirani o'z vaqtida bo'shata olmaydi, bu esa bir nechta Bitmap to'planganda yetarli Java xotirasi bo'lsa ham OOM ga olib keladi.
Retain cycle — ARC da ikkita ob'ekt bir-biriga kuchli havolalar saqlaganda va havola soni hech qachon nolga yetmaganda yuz beradi. Oddiy misol: ViewController ning closure ga kuchli havolasi va closure ning self ni kuchli tutishi. Yechim: closure-larda [weak self] yoki [unowned self] ishlating.
Xotira hajmi qurilma va Android versiyasiga bog'liq. Eski qurilmalar uchun (API 15-24) — 64-128 MB. Zamonaviy qurilmalar uchun (API 25+) — 256-512 MB. Aniq qiymatni ActivityManager.getMemoryClass() orqali olish mumkin. Katta ilovalar (o'yinlar, muharrirlar) uchun manifestda largeHeap=true mavjud, 1 GB gacha beradi.
Xulosa
Biz kalit topshirig'i bilan mobil ilovani ishlab chiqamiz
IT Sectr 2017-yildan beri startaplar va korxonalar uchun iOS va Android ilovalarini yaratadi. Biz sizga maslahat beramiz va eng yaxshi yechimni taklif qilamiz.
Shuningdek o'qing