Tutilib qolish — bu mobil ilova sekin va beqaror ishlayotgan vaziyatning foydalanuvchi tavsifi: ba'zida normal javob beradi, ba'zida to'satdan bir necha soniyaga muzlab qoladi. Texnik kontekstda “tutilib qolish” tez-tez GC pauzalari, asosiy oqimning sinxron operatsiyalar bilan bloklanishi va optimal bo'lmagan ma'lumotlar tuzilmalari natijasida yuzaga keladigan laglar va mikro-muzlashlar kombinatsiyasini anglatadi. Android Performance Benchmarking Guide ma'lumotlariga ko'ra, javob vaqtini 300 ms dan 100 ms gacha kamaytirish foydalanuvchilarni saqlab qolishni 25% ga oshiradi. Tutilib qolish diagnostikasi axlat yig'ish chastotasini tahlil qilish bilan CPU va Memory profillashni birlashtirishni talab qiladi.
Asosiy ma'lumotlar
Tutilib qolish — foydalanuvchilar sub'ektiv ravishda sekin ilova ishini tasvirlash uchun ishlatadigan norasmiy atama. Doimiy kechikish sifatida namoyon bo'ladigan lagdan farqli o'laroq, tutilib qolish tartibsiz muzlashlardir: ilova bir necha soniya mukammal ishlashi mumkin, keyin 1–3 soniya “o'ylab qoladi”.
Profillash nuqtai nazaridan, tutilib qolish 100 ms dan ortiq cho'qqi kechikishlari bilan o'tkazib yuborilgan kadrlar seriyasi (jank) sifatida namoyon bo'ladi. FPS grafigida bu keskin pasayishlar kabi ko'rinadi: 60 → 20 → 55 → 10 kadr/sekund. Bir xil past FPS bilan lagdan farqli o'laroq, tutilib qolish aniq o'zgaruvchanlikka ega.
Ilova tutilib qolganda, foydalanuvchi sekinlashish mantig'ini tushunmaydi: ekran silliq siljishi mumkin, keyin to'satdan bir soniyaga to'xtab qolishi mumkin. Bu umidsizlikka sabab bo'ladi va ilovaga ishonchni kamaytiradi. Google ma'lumotlariga ko'ra, foydalanuvchilarning 53% yuklash 3 soniyadan ortiq davom etsa, sayt yoki ilovani tark etadi.
Tutilib qolishning tartibsiz xarakteri muammo doimiy ortiqcha yuklanishdan emas, balki hodisa omillaridan kelib chiqqanligini ko'rsatadi. Oddiy stsenariylarni ko'rib chiqaylik.
Android-da ART muhitida axlat yig'ish ilovaning barcha oqimlarini to'xtatadi. Agar kodda ko'plab vaqtinchalik ob'ektlar yaratilsa — masalan, har bir onBindViewHolder chaqiruvida konkatenatsiya orqali yangi String yaratilsa — GC tez-tez ishga tushadi. Pauza yig'in hajmi va ob'ekt avlodiga qarab 5–50 ms davom etishi mumkin. Foydalanuvchi buni to'satdan “o'ylash” kabi his qiladi.
Room Android va Core Data iOS-da asinxron so'rovlarni qo'llab-quvvatlaydi, ammo dasturchilar ko'pincha soddalik uchun getValue() chaqiradi yoki runBlocking orqali so'rovni bajaradi. 10 000 qatorli jadvalda joinlar bilan og'ir SELECT 200–500 ms davom etishi va UI-ni butunlay bloklashi mumkin.
Kamera tasvirini (12 Mp, 4000x3000 px) masshtablamasdan yuklash Bitmap-ga dekodlash uchun 200 ms gacha davom etadi. Tasvirlar asinxron yuklansa, lekin cheklovli oqim hovuzisiz, bir vaqtning o'zida 5–6 dekodlashni ishga tushirish CPU-ni haddan tashqari yuklab, ko'chib yuruvchi sekinlashishlarga sabab bo'lishi mumkin.
Tartibsiz sekinlashishlarni diagnostika qilish doimiy lagni diagnostika qilishdan qiyinroq, chunki muammo har ishga tushirishda takrorlanmasligi mumkin. Uzoq vaqt davomida statistika yig'ish talab qilinadi.
Android Studio Memory Profiler nafaqat xotira ishlatilishini, balki GC hodisalarini ham ko'rsatadi: chastota, tur (Concurrent, Full), davomiylik. Agar GC tinch holatda 5 soniyada 1 martadan ortiq sodir bo'lsa — bu haddan tashqari alokatsiya belgisidir. Tutilib qolish vaqtida heap dump yozish qaysi ob'ektlar xotirani egallaganini ko'rishga imkon beradi.
iOS-da ob'ektlarni yaratish va bo'shatishni kuzatish uchun Instruments-da Allocations shablonidan foydalaning. Avlodlarni (Generations) yoqing — ular harakatlar orasida yig'in suratlarini olishga va qaysi ob'ektlar xotirada qolayotganini ko'rishga imkon beradi. Bo'shatilmaydigan Persistent objects — xotira to'planishi va keyingi pauzalarning manbai.
JankStats — real vaqtda o'tkazib yuborilgan kadrlar metrikalarini to'playdigan Android kutubxonasi. Har bir jankni joriy stsenariyga (masalan, “ro'yxatni aylantirish”, “ekranni ochish”) bog'laydi, bu tutilib qolish aynan qaysi harakatda sodir bo'lishini tushunishga imkon beradi.
Android-da muzlashlarni kuzatish uchun JankStats integratsiyasi namunasi:
class MainActivity : AppCompatActivity() {
private lateinit var jankStats: JankStats
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
jankStats = JankStats.create(this.window.decorView) { frameData ->
if (frameData.isJank()) {
Log.w("Jank", "Duration=${frameData.durationMs}ms")
}
}
}
}
Tutilib qolishni bartaraf etish har bir sabab bilan maqsadli ishlashni talab qiladi. Universal yechim yo'q — aniq unumdorlik profillarini tahlil qilish kerak.
Agar ro'yxat 1000+ elementni o'z ichiga olgan bo'lsa va hammasi birdan yuklansa — bu kafolatlangan tutilib qolishdir. Android-da Paging 3 va iOS-da NSFetchedResultsController ma'lumotlarni aylantirish paytida qismlarga bo'lib yuklaydi. Foydalanuvchi faqat birinchi 10–20 elementni ko'radi, qolganlari fonda yuklanadi.
Room Android Studio-da Inspection Tool orqali so'rovlarni profillash imkonini beradi: bajarilish vaqti, qaytarilgan qatorlar soni va so'rov rejasi ko'rinadi. WHERE va ORDER BY ustunlariga indekslar qo'shish so'rov vaqtini 300 ms dan 5 ms gacha kamaytirishi mumkin. iOS-da shunga o'xshash tekshirish Instruments-da Core Data Profiler tomonidan amalga oshiriladi.
Fon sinxronizatsiyalari, fayl yuklashlar, ma'lumotlarni qayta ishlash — bularning barchasi WorkManager (Android) yoki Background Tasks (iOS) orqali bajarilishi kerak. Agar sinxronizatsiya UI oqimida ishga tushirilsa, ilova bajarilish vaqtida tutilib qoladi. WorkManager batareya va tarmoq holatini hisobga olgan holda fon oqimida bajarilishni kafolatlaydi.
Android-da WorkManager orqali fon sinxronizatsiyasi namunasi:
class SyncWorker(context: Context, params: WorkerParameters)
: CoroutineWorker(context, params) {
override suspend fun doWork(): Result {
return try {
Log.d("Sync", "Fon oqimida ma'lumotlarni sinxronlash")
syncData()
Result.success()
} catch (e: Exception) {
Result.retry()
}
}
}
Tutilib qolishning oldini olish kod yozish bosqichida, xotira va oqimlar bilan samarali ishlash tamoyillariga rioya qilish orqali mumkin.
Baseline Profiles — Android oldindan (AOT) kompilyatsiya qiladigan sinflar va metodlar ro'yxati. Profilsiz har bir yangi ekran birinchi ochilishda kompilyatsiya qilinadi va 100–500 ms kechikishga sabab bo'ladi. Asosiy ekranlar uchun Baseline Profile tayyorlang va baseline-profile-gradle-plugin orqali Gradle-da generatsiyani yoqing.
Hot path — har bir kadrda bajariladigan kod: onBindViewHolder, draw, layoutSubviews. Ushbu metodlarda ob'ekt yaratishdan saqlaning: ob'ekt hovuzidan foydalaning, konkatenatsiya o'rniga StringBuilder, formatlangan satrlar va formatlarni keshlang. Har bir qo'shimcha alokatsiya keyingi GC ni yaqinlashtiradi.
CI pipeline-ga ro'yxatni aylantirish va ekranni ochish stsenariysi bilan Macrobenchmark ishga tushirishni qo'shing. Chegara belgilang: kadr vaqtining 99-persentili 16 ms dan oshmasligi kerak. Agar chegara oshib ketsa — build optimallashtirishgacha rad etiladi.
Tez-tez beriladigan savollar
Lag — doimiy kechikish (masalan, har bir bosishda 200 ms). Tutilib qolish — tartibsiz: ilova normal ishlaydi, keyin to'satdan 1–3 soniya sekinlashadi, keyin yana normal. Sabab — GC pauzalari yoki ma'lumotlar bazasiga sinxron so'rovlar kabi hodisa omillari.
Android Studio-da Memory Profiler dan foydalaning: Memory yorlig'i GC hodisalarini davomiyligi bilan ko'rsatadi. Ishlab chiqarish monitoringi uchun maxsus treyslar bilan Firebase Performance Monitoring-ni ulang. iOS-da Malloc Debug-ni yoqing va Instruments-da alokatsiya avlodlarini belgilang.
Bilvosita — ha. Server javobi kechikish bilan kelsa va UI uni sinxron kutayotgan bo'lsa, ilova muzlab qoladi. Agar so'rov asinxron bo'lsa, lekin javobni qayta ishlash UI oqimida amalga oshirilsa — bu ham tutilib qolishga sabab bo'ladi. Yechim — korutinlar va taraqqiyot ko'rsatkichlari bilan asinxron qayta ishlash.
Noto'g'ri ishlatilganda KMP interoperabellik uchun ortiqcha o'rama ob'ektlarni yaratishi mumkin. iOS-da bu alokatsiya chastotasini va natijada ARC pauzalarini oshiradi. @ObjCName dan foydalaning, expect/actualni optimallashtiring va UI ning issiq yo'llaridan umumiy kodga tez-tez murojaat qilishdan saqlaning.
android:largeHeap="true" orqali yig'inni oshirish GC ni keviktirishadi, lekin alokatsiya sababini bartaraf etmaydi. GC nihoyat ishga tushganda, pauza uzoqroq bo'ladi, chunki ko'proq ob'ektlarni aylanib o'tish kerak. Yechim — alokatsiyalar sonini kamaytirish, yig'inni kengaytirish emas.
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