Dasturlashda muzlash — mohiyati, sabablari va oldini olish

Muallif: IT Sectr Nashr etilgan: 2026-07-28 O'qish vaqti: 9 daq

Muzlash (visnet) — mobil ilovaning foydalanuvchining har qanday harakatlariga uzoq vaqt davomida javob bermaslik holati. Laglar (sekinlashish) va glitchlardan (noto'g'ri xatti-harakat) farqli o'laroq, muzlash UI-ni to'liq bloklaydi: teginishlar qayta ishlanmaydi, animatsiya to'xtaydi, ekran „muzlaydi". Sabab — bosh oqimning sinxron operatsiya bilan bloklanishi, ko'p oqimli koddagi deadlock yoki anomal uzoq axlat yig'ish. Apple Main Thread Checker Documentation ma'lumotlariga ko'ra, iOS-dagi crash hisobotlarining 40% dan ortig'i bosh oqimning bloklanishi bilan bog'liq. Android-da shunga o'xshash vaziyat ANR — „Ilova javob bermaydi" tizim dialogiga olib keladi.

Asosiy fikrlar

  • Muzlash — UI-ning uzoq vaqt (soniyalar va o'nlab soniyalar) davomida to'liq bloklanishi, laglar va glitchlardan farqlanadi
  • Asosiy sabablar — bosh oqimning kirish-chiqish bilan bloklanishi, oqimlar o'rtasida deadlock, cheksiz sikl va uzoq GC bilan xotira oqishi
  • Tashxis iOS-da Main Thread Checker, Android-da ANR loglari /data/anr/traces.txt va oqim dump tahlilini o'z ichiga oladi
  • Bartaraf etish — barcha potentsial uzoq operatsiyalarni fon oqimlariga o'tkazish, Structured Concurrency dan foydalanish va UI oqimida synchronized dan qochish
  • Profilaktika — StrictMode, Debug sxemasida Main Thread Checker, deadlock uchun statik tahlil va javob vaqtini o'lchash bilan davriy testlar

Mobil dasturlashda muzlash nima

Muzlash (freeze, hang) mobil ilovada — ilovaning bir necha soniya yoki undan ko'proq vaqt davomida kirish hodisalarini qayta ishlashni va interfeysni yangilashni to'xtatish holatidir. Texnik jihatdan bu bosh oqim (main thread) bloklanganligini va keyingi runner siklini bajara olmasligini anglatadi.

Muzlashning lag va ANR dan farqi

Lag — 500 ms gacha kechikish bo'lib, foydalanuvchi sekinlashishni sezadi, ammo ilova ishlashda davom etadi. Muzlash 1 soniyadan o'nlab soniyagacha davom etadi. Android-da ANR — 5 soniyadan ortiq davom etgan va tizim tomonidan aniqlangan muzlashning alohida holatidir. Har bir muzlash ANR ga olib kelmaydi, lekin har bir ANR hujjatlashtirilgan muzlashdir.

Muzlashning oqibatlari

Android-da 5 soniyadan ortiq muzlash ilovani yopish taklifi bilan ANR dialogini chaqiradi. iOS-da tizim watchdogga ega — agar ilova 10–20 soniya davomida hodisalarga javob bermasa, Watchdog jarayonni 0x8badf00d (ate bad food) kodi bilan tugatadi. Foydalanuvchi ilovaning to'satdan yopilishini va asosiy ekranga qaytishini ko'radi.

Android va iOS-da muzlash sabablari

100 ms dan ortiq davom etadigan va bosh oqimda ishga tushirilgan har qanday operatsiya potentsial ravishda muzlashga olib keladi. Bloklanishlarning asosiy manbalarini ko'rib chiqamiz.

UI oqimida sinxron kirish-chiqish

Katta faylni o'qish, asinxron bo'lmagan tarmoq so'rovi, SharedPreferences da apply va keyin commit sinxron usuli bilan ma'lumotlarni saqlash — bularning barchasi bosh oqimni bloklaydi. Android-da 10 MB faylni sinxron o'qish flesh xotira tezligiga qarab 200–500 ms davom etishi mumkin. iOS-da completionHandler siz URLSession sinxron yuklanishi server javobi vaqtida UI-ni bloklaydi.

Ko'p oqimli kodeda deadlock

Ikki oqim bir-biri tomonidan ushlab turilgan resurslarning bo'shatilishini kutganda deadlock yuzaga keladi. Mobil ilovalarda odatiy stsenariy — A oqimi Lock1 ni bloklaydi va Lock2 ni kutadi, B oqimi esa Lock2 ni bloklaydi va Lock1 ni kutadi. Ikkala oqim ham abadiy muzlaydi. Agar ulardan biri bosh oqim bo'lsa, ilova butunlay muzlaydi.

Cheksiz sikl yoki rekursiya

Mantiqdagi xato — masalan, chiqish shartisiz while(true) yoki bazaviy holatsiz rekursiya — bosh oqimda cheksiz bajarilishga olib keladi. Android buni 5 soniyadan keyin ANR orqali aniqlaydi, iOS esa Stackshot orqali, cheksiz takrorlanuvchi chaqiruv stekini qayd etadi.

  • Android — yopilmagan Cursor, enqueue() o'rniga execute() orqali sinxron so'rov, UI oqimida FileInputStream.read()
  • iOS — performSelectorOnMainThread:withObject:waitUntilDone:YES, NSURLConnection sendSynchronousRequest ishga tushirish, dataWithContentsOfURL bilan tasvir yuklash
  • Kross-platforma — ajratilgan isolatesiz Flutter compute, sinxron NativeModule bilan React Native

Muzlashni qanday aniqlash mumkin

Muzlash tashxisi bloklanish vaqtida barcha oqimlarning holatini qayd eta oladigan asboblarni talab qiladi.

Android-da ANR loglari

Har bir ANR da Android tizimi ilovaning har bir oqimining stek dumpini o'z ichiga olgan /data/anr/traces.txt faylini saqlaydi. Ushbu faylning tahlili — asosiy tashxis usuli: main oqimini topish va u qaysi metodda to'xtaganini ko'rish kerak. Stek Thread.sleep, InputStream.read yoki Lock.lock bilan tugasa, sabab topilgan.

iOS-da Stackshot

Xcode ilova muzlaganda (SIGSTOP signali) Stackshot — barcha oqimlarning stek tasvirini olishi mumkin. Sxemada „Logging" → „Include Stackshot Logs" ni yoqing. 0x8badf00d kodi bilan qulaganda Devices & Simulators dan crash logini chiqarib, muzlagan stek bilan com.apple.main-thread oqimini toping.

Xcode da Main Thread Checker

Main Thread Checker ilova ishlayotganda fon oqimlaridan UIKit chaqiruvlarini avtomatik aniqlaydi. Uni sxemada yoqing (Diagnostics → Main Thread Checker). Har bir ogohlantirish potentsial muzlash sababidir, ayniqsa tarmoq so'rovining completionHandler yopilishida yuz bersa.

Android-da StrictMode orqali bloklanishni aniqlash namunasi:

kotlin
class App : Application() {
    override fun onCreate() {
        super.onCreate()
        StrictMode.setVmPolicy(StrictMode.VmPolicy.Builder()
            .detectLeakedSqlLiteObjects()
            .detectLeakedClosableObjects()
            .penaltyLog()
            .build())
        StrictMode.setThreadPolicy(StrictMode.ThreadPolicy.Builder()
            .detectAll()
            .penaltyDeath()
            .build())
    }
}

UI bloklanishlarini bartaraf etish usullari

Muzlashni bartaraf etish barcha potentsial uzoq operatsiyalarni fon oqimlariga o'tkazish bilan boshlanadi. Har bir platforma uchun aniq texnikalarni ko'rib chiqamiz.

Korutinlar bilan Structured Concurrency

Kotlin Coroutines viewModelScope.launch(Dispatchers.IO) bilan tarmoq operatsiyasi yoki ma'lumotlar bazasidan o'qish fon oqimida bajarilishini kafolatlaydi. Dispatchers.Main faqat UI yangilash uchun ishlatiladi. Muhim: barcha suspend funksiyalar tuzilgan bo'lishi kerak — bolakay korutinlar ota-ona bekor qilinganda bekor qilinadi, oqim oqishining oldini oladi.

iOS-da asinxron navbatlar

Grand Central Dispatch fon vazifalari uchun DispatchQueue.global(qos: .userInitiated) va UI yangilash uchun DispatchQueue.main.async — standart naqsh. Bosh navbatda sync() dan qoching — bu kafolatlangan deadlock. Async/await (Swift 5.5+) dan o'qilishi oson asinxron kod uchun foydalaning, MainActor orqali avtomatik ravishda bosh oqimga qaytish bilan.

UI oqimida synchronized dan qochish

Kotlin da synchronized bloklari va Swift da @synchronized bosh oqimida xavflidir: agar boshqa oqim allaqachon bu blokirovkani egallagan bo'lsa, bosh oqim kutishda muzlaydi. Blokirovkalar o'rniga atomik turlardan (AtomicInteger, Swift da atomik xususiyatlar) yoki ketma-ket navbatlardan foydalaning.

Android-da korutinlar bilan asinxron ma'lumot yuklash namunasi:

kotlin
class DataViewModel : ViewModel() {
    private val _data = MutableStateFlow<List<Item>>(emptyList())
    val data: StateFlow<List<Item>> = _data.asStateFlow()

    fun loadData() {
        viewModelScope.launch(Dispatchers.IO) {
            val result = fetchFromNetwork()
            _data.emit(result)
        }
    }
}

Rivojlanish bosqichida muzlashning oldini olish

Muzlashning oldini olish asboblar kombinatsiyasi, arxitektura tamoyillari va kod ko'rib chiqish jarayonlari bilan tizimli ravishda yordam beradi.

penaltyDeath bilan StrictMode

Oqim siyosatlari uchun StrictMode ni penaltyDeath bilan sozlang — bu bosh oqimda tarmoq chaqiruvi yoki disk kirish-chiqishi aniqlanganda ilovaning darhol qulashiga olib keladi. Dasturchi muammoni e'tiborsiz qoldira olmaydi. Ishlab chiqarish qurilishida qulashsiz statistika to'plash uchun penaltyLog dan foydalaning.

Debug sxemasida Main Thread Checker

iOS da Debug sxemasida Main Thread Checker ni yoqing va CI ni ushbu parametr bilan testlarni ishga tushirishga sozlang. Agar test fon oqimidan UIKit chaqiruvini o'z ichiga olsa, muvaffaqiyatsiz bo'lishi kerak. Bu TestFlight ga yuborishdan oldin muammoni aniqlashning yagona ishonchli usulidir.

Ko'p oqimlilikni tekshirish bilan kod ko'rib chiqish

Kod ko'rib chiqish jarayoniga majburiy band qo'shing: har qanday tarmoq chaqiruvi, fayllar bilan ishlash, ma'lumotlar bazasi yoki og'ir hisoblashlar fon oqimida bajarilishini tekshiring. Deadlock statik analizator bilan aniqlanishi mumkin: Facebook dan Infer va Xcode dan Thread Safety Checker ishga tushirishdan oldin potentsial blokirovkalarni topadi.

  • Android — StrictMode, Infer, Android Lint Multithread, viewModelScope bilan Kotlin Coroutines
  • iOS — Main Thread Checker, TSAN (Thread Sanitizer), Xcode Analyze, MainActor bilan Swift async/await
  • Kross-platforma — Flutter compute isolate, requestAnimationFrame bilan React Native interaction manager

Tez-tez beriladigan savollar

Muzlash va ANR o'rtasidagi farq nima?

ANR (Application Not Responding) — Android ning tizim bildirishnomasi bo'lib, bosh oqim 5 soniyadan ortiq muzlaganda paydo bo'ladi. Muzlash kengroq tushunchadir: har qanday davomiylikdagi UI bloklanishi. iOS da ANR yo'q, lekin 10–20 soniya vaqt chegarasi bilan Watchdog mavjud.

Android da traces.txt ni qanday o'qish mumkin?

Fayl /data/anr/traces.txt manzilida joylashgan. Kirish uchun root yoki adb shell talab qilinadi: adb shell cat /data/anr/traces.txt \> traces.txt ni root huquqlari bilan bajaring. Stekda „main" oqimini toping — oxirgi chaqirilgan metod bloklanish sababini ko'rsatadi.

Nega ilova iOS da muzlaydi, lekin qulab tushmaydi?

Agar muzlash 10 soniyadan kam davom etsa, Watchdog ishga tushmaydi va ilova blokirovka qiluvchi operatsiya tugaguncha shunchaki „muzlab" qoladi. Foydalanuvchi qulashni ko'rmaydi, lekin xafa bo'ladi. Bunday holatlarni aniqlash uchun MetricKit dan bajarilish vaqtining maxsus izlari bilan foydalaning.

Ilovani muzlash uchun qanday test qilish kerak?

Ekran 1 soniyadan kamroq vaqtda ochilishini tekshiradigan UI testlari dan foydalaning. CI ga teginish va keyingi ekran paydo bo'lishi o'rtasidagi vaqtni o'lchashni qo'shing. Android da asinxron operatsiyalarni kutish uchun IdlingResource bilan Espresso dan foydalaning. iOS da yuklash vaqtini tekshirish uchun XCTWaiter bilan XCTest.

SwiftUI muzlashga sabab bo'lishi mumkinmi?

SwiftUI o'z-o'zidan muzlashga sabab bo'lmaydi, lekin body xususiyatidagi murakkab hisoblashlar — ha. Body og'ir operatsiyalar tufayli 500 ms hisoblansa, UI muzlaydi. Yechim — hisoblashlarni Task.detached ga o'tkazing va @State ni asosiy aktyorda asinxron yangilang.

Xulosa

  • Muzlash — bosh oqim bloklanishi, deadlock yoki cheksiz sikl natijasida UI ning soniyalar va o'nlab soniyalar davomida to'liq bloklanishi
  • Tashxis — Android da /data/anr/traces.txt, iOS da Stackshot va Main Thread Checker
  • Asosiy sabablar — sinxron kirish-chiqish, oqimlar o'rtasida deadlock, cheksiz rekursiya, uzoq GC
  • Bartaraf etish — to'g'ri dispetcherlar bilan korutinlar, MainActor bilan async/await, barcha IO operatsiyalarini fon oqimlariga o'tkazish
  • Profilaktika — penaltyDeath bilan StrictMode, Main Thread Checker, deadlock statik tahlili (Infer, TSAN)
  • Android da muzlash > 5 s = ANR; iOS da > 10–20 s = Watchdog crash (0x8badf00d)
  • Tavsiya: Debug sxemasida Thread Sanitizer ni yoqing va CI ni data race va deadlock aniqlash uchun TSAN bilan testlarni ishga tushirishga sozlang

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.

Loyihani muhokama qilish

Shuningdek o'qing