Proqramlaşdırmada donma — mahiyyəti, səbəbləri və qarşısının alınması

Müəllif: IT Sectr Dərc olunub: 2026-07-28 Oxuma vaxtı: 9 dəq

Donma (visnet) — mobil proqramın istifadəçinin hər hansı hərəkətinə uzun müddət cavab verməməsi halıdır. Laqlar (yavaşlama) və qlitchlərdən (səhv davranış) fərqli olaraq, donma UI-ni tamamilə bloklayır: toxunuşlar işlənmir, animasiya dayanır, ekran „donur". Səbəb — əsas axının sinxron əməliyyatla bloklanması, çoxaxınlı kodda deadlock və ya anormal uzun zibil yığımıdır. Apple Main Thread Checker Documentation-nın məlumatına görə, iOS crash raportlarının 40%-dən çoxu əsas axının bloklanması ilə bağlıdır. Android-də oxşar vəziyyət ANR — „Proqram cavab vermir" sistem dialoquna gətirib çıxarır.

Əsas məqamlar

  • Donma — UI-nin uzun müddətə (saniyələr və onlarla saniyə) tam bloklanması, laqlardan və qlitchlərdən fərqlənir
  • Əsas səbəblər — əsas axının giriş-çıxışla bloklanması, axınlar arasında deadlock, sonsuz dövr və uzun GC ilə yaddaş sızması
  • Diaqnostika iOS-da Main Thread Checker, Android-də ANR loqları /data/anr/traces.txt və axın dump analizini əhatə edir
  • Aradan qaldırma — bütün potensial uzun əməliyyatların fon axınlarına daşınması, Structured Concurrency istifadəsi və UI axınında synchronized-dən qaçınma
  • Profilaktika — StrictMode, Debug sxemində Main Thread Checker, deadlock üçün statik analiz və cavab müddətinin ölçülməsi ilə dövri testlər

Mobil proqramlaşdırmada donma nədir

Donma (freeze, hang) mobil proqramda — proqramın bir neçə saniyə və daha çox müddət ərzində giriş hadisələrini emal etməyi və interfeysi yeniləməyi dayandırması halıdır. Texniki olaraq bu o deməkdir ki, əsas axın (main thread) bloklanıb və növbəti runner dövrünü icra edə bilmir.

Donmanın laq və ANR-dən fərqi

Laq — 500 ms-ə qədər gecikmədir, bu zaman istifadəçi yavaşlama hiss edir, lakin proqram işləməyə davam edir. Donma 1 saniyədən onlarla saniyəyə qədər davam edir. Android-də ANR — 5 saniyədən çox davam edən və sistem tərəfindən aşkarlanan donmanın xüsusi halıdır. Hər donma ANR-yə gətirib çıxarmır, lakin hər ANR sənədləşdirilmiş donmadır.

Donmanın nəticələri

Android-də 5 saniyədən uzun donma proqramı bağlamaq təklifi ilə ANR dialoqu yaradır. iOS-da sistem watchdoga malikdir — proqram 10–20 saniyə ərzində hadisələrə reaksiya vermirsə, Watchdog prosesi 0x8badf00d (ate bad food) kodu ilə bitirir. İstifadəçi proqramın qəfil bağlanmasını və ana ekrana qayıtmasını görür.

Android və iOS-də donma səbəbləri

100 ms-dən uzun çəkən və əsas axında işə salınan hər hansı əməliyyat potensial olaraq donmaya səbəb olur. Blokadaların əsas mənbələrinə baxaq.

UI axınında sinxron giriş-çıxış

Böyük faylın oxunması, asinxron olmayan şəbəkə sorğusu, SharedPreferences-də apply və ardınca commit sinxron metodu ilə məlumatların saxlanması — bütün bu əməliyyatlar əsas axını bloklayır. Android-də 10 MB faylın sinxron oxunması flash yaddaşın sürətindən asılı olaraq 200–500 ms çəkə bilər. iOS-da completionHandler olmadan URLSession sinxron yüklənməsi server cavabı müddətində UI-ni bloklayır.

Çoxaxınlı kodda deadlock

İki axın bir-birinin saxladığı resursların boşalmasını gözlədikdə deadlock yaranır. Mobil proqramlarda tipik ssenari — A axını Lock1-i bloklayır və Lock2-ni gözləyir, B axını isə Lock2-ni bloklayır və Lock1-i gözləyir. Hər iki axın əbədi donur. Əgər onlardan biri əsas axındırsa, proqram tamamilə donur.

Sonsuz dövr və ya rekursiya

Məntiq səhvi — məsələn, çıxış şərti olmayan while(true) və ya baza halı olmayan rekursiya — əsas axında sonsuz icraya gətirib çıxarır. Android bunu 5 saniyədən sonra ANR vasitəsilə aşkarlayır, iOS isə sonsuz təkrarlanan çağırış stackini qeyd edən Stackshot vasitəsilə.

  • Android — bağlanmayan Cursor, enqueue() əvəzinə execute() ilə sinxron sorğu, UI axınında FileInputStream.read()
  • iOS — performSelectorOnMainThread:withObject:waitUntilDone:YES, NSURLConnection sendSynchronousRequest-in işə salınması, dataWithContentsOfURL ilə şəkil yükləmə
  • Cross-platform — ayrılmış isolate olmadan Flutter compute, sinxron NativeModule ilə React Native

Donmanı necə diaqnoz etmək olar

Donmanın diaqnostikası blokada anında bütün axınların vəziyyətini qeyd edə bilən alətlər tələb edir.

Android-də ANR loqları

Hər ANR zamanı Android sistemi proqramın hər bir axınının stack dumpini ehtiva edən /data/anr/traces.txt faylını saxlayır. Bu faylın təhlili — əsas diaqnostika üsuludur: main axınını tapmaq və onun hansı metoddə dayandığını görmək lazımdır. Stack Thread.sleep, InputStream.read və ya Lock.lock ilə bitirsə, səbəb tapılıb.

iOS-da Stackshot

Xcode proqram donduqda (SIGSTOP siqnalı) Stackshot — bütün axınların stack şəklini çəkə bilər. Sxemdə „Logging" → „Include Stackshot Logs"-u aktivləşdirin. 0x8badf00d kodu ilə çökdükdə Devices & Simulators-dən crash loqunu çıxarın və donmuş stack ilə com.apple.main-thread axınını tapın.

Xcode-da Main Thread Checker

Main Thread Checker proqramın işləməsi zamanı fon axınlarından UIKit çağırışlarını avtomatik aşkarlayır. Sxemdə aktivləşdirin (Diagnostics → Main Thread Checker). Hər xəbərdarlıq potensial donma səbəbidir, xüsusilə şəbəkə sorğusunun completionHandler bağlanmasında baş verərsə.

Android-də StrictMode vasitəsilə blokadanın aşkarlanması nümunəsi:

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 blokadalarının aradan qaldırılması üsulları

Donmanın aradan qaldırılması bütün potensial uzun əməliyyatların fon axınlarına daşınması ilə başlayır. Hər platforma üçün konkret texnikalara baxaq.

Korutinlər ilə Structured Concurrency

Kotlin Coroutines viewModelScope.launch(Dispatchers.IO) ilə şəbəkə əməliyyatının və ya verilənlər bazası oxumasının fon axınında yerinə yetirilməsini təmin edir. Dispatchers.Main yalnız UI yeniləmək üçün istifadə olunur. Vacibdir: bütün suspend-funksiyalar strukturlaşdırılmış olmalıdır — uşaq korutinlar valideyn ləğv edildikdə ləğv edilir, axın sızmasının qarşısını alır.

iOS-da asinxron növbələr

Grand Central Dispatch fon tapşırıqları üçün DispatchQueue.global(qos: .userInitiated) və UI yeniləmək üçün DispatchQueue.main.async — standart nümunədir. Əsas növbədə sync()-dən qaçının — bu zəmanətli deadlockdur. Daha oxunaqlı asinxron kod üçün async/await (Swift 5.5+) istifadə edin, MainActor vasitəsilə əsas axına avtomatik qayıdışla.

UI axınında synchronized-dən qaçınma

Kotlin-də synchronized blokları və Swift-də @synchronized əsas axınında təhlükəlidir: əgər başqa bir axın artıq bu blokadanı ələ keçiribsə, əsas axın gözləmədə donacaq. Blokadalar əvəzinə atomik tiplərdən (AtomicInteger, Swift-də atomik xüsusiyyətlər) və ya ardıcıl növbələrdən istifadə edin.

Android-də korutinlər ilə asinxron məlumat yükləmə nümunəsi:

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)
        }
    }
}

İnkişaf mərhələsində donmanın profilaktikası

Donmanın qarşısının alınması alətlər kombinasiyası, memarlıq prinsipləri və kod icmalı prosesləri ilə sistemli şəkildə kömək edir.

penaltyDeath ilə StrictMode

Axın siyasətləri üçün StrictMode-u penaltyDeath ilə konfiqurasiya edin — bu, əsas axında şəbəkə çağırışı və ya disk giriş-çıxışı aşkar edildikdə proqramın dərhal çökməsinə səbəb olacaq. Tərtibatçı problemi görməməzlikdən gələ bilməyəcək. İstehsal quruluşunda çökmədən statistik toplamaq üçün penaltyLog istifadə edin.

Debug sxemində Main Thread Checker

iOS-da Debug sxemində Main Thread Checker-ı aktivləşdirin və CI-ni bu seçimlə testləri işə salmaq üçün konfiqurasiya edin. Test fon axınından UIKit çağırışı ehtiva edərsə, uğursuz olmalıdır. Bu, TestFlight-a göndərməzdən əvvəl problemi aşkar etməyin yeganə etibarlı yoludur.

Çoxaxınlılıq yoxlanışı ilə kod icmalı

Kod icmalı prosesinə məcburi bənd əlavə edin: hər hansı şəbəkə çağırışının, fayllarla işin, verilənlər bazası və ya ağır hesablamaların fon axınında yerinə yetirildiyini yoxlayın. Deadlock statik analizatorla aşkar edilə bilər: Facebook-dan Infer və Xcode-dan Thread Safety Checker işə salınmadan əvvəl potensial blokadaları tapır.

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

Tez-tez verilən suallar

Donma və ANR arasında fərq nədir?

ANR (Application Not Responding) — Android-in sistem bildirişidir, əsas axının 5 saniyədən çox donması zamanı görünür. Donma daha geniş anlayışdır: istənilən müddətli UI blokadası. iOS-da ANR yoxdur, lakin 10–20 saniyə vaxt aşımı olan Watchdog var.

Android-də traces.txt-i necə oxumaq olar?

Fayl /data/anr/traces.txt ünvanında yerləşir. Giriş üçün root və ya adb shell tələb olunur: adb shell cat /data/anr/traces.txt \> traces.txt root hüquqları ilə yerinə yetirin. Stackdə „main" axınını tapın — son çağırılan metod blokadanın səbəbini göstərir.

Niyə proqram iOS-da donur, amma çökmür?

Donma 10 saniyədən az davam edərsə, Watchdog işə düşmür və proqram sadəcə blokada əməliyyatı bitənə qədər „donur". İstifadəçi çökmə görmür, lakin məyusluq yaşayır. Belə halları aşkar etmək üçün MetricKit-dən icra müddətinin xüsusi izləri ilə istifadə edin.

Proqramı donma üçün necə test etmək olar?

Ekranın 1 saniyədən az müddətdə açıldığını yoxlayan UI testləri istifadə edin. CI-ə toxunma və növbəti ekranın görünməsi arasında vaxt ölçməsi əlavə edin. Android-də asinxron əməliyyatları gözləmək üçün IdlingResource ilə Espresso istifadə edin. iOS-da yükləmə vaxtını yoxlamaq üçün XCTWaiter ilə XCTest.

SwiftUI donmaya səbəb ola bilərmi?

SwiftUI özlüyündə donmaya səbəb olmur, lakin body xassəsində mürəkkəb hesablamalar — bəli. Body ağır əməliyyatlar səbəbindən 500 ms hesablanırsa, UI donur. Həll yolu — hesablamaları Task.detached-ə daşımaq və @State-i əsas aktyorda asinxron yeniləməkdir.

Xülasə

  • Donma — əsas axının blokadası, deadlock və ya sonsuz dövr nəticəsində UI-nin saniyələr və onlarla saniyə tam bloklanması
  • Diaqnostika — Android-də /data/anr/traces.txt, iOS-da Stackshot və Main Thread Checker
  • Əsas səbəblər — sinxron giriş-çıxış, axınlar arasında deadlock, sonsuz rekursiya, uzun GC
  • Aradan qaldırma — düzgün dispetçerlərlə korutinlər, MainActor ilə async/await, bütün IO əməliyyatlarının fon axınlarına daşınması
  • Profilaktika — penaltyDeath ilə StrictMode, Main Thread Checker, deadlock statik analizi (Infer, TSAN)
  • Android-də donma > 5 s = ANR; iOS-da > 10–20 s = Watchdog crash (0x8badf00d)
  • Tövsiyə: Debug sxemində Thread Sanitizer-ı aktivləşdirin və CI-ni data race və deadlock aşkarlamaq üçün TSAN ilə testləri işə salmağa konfiqurasiya edin

Açar təslim mobil tətbiq hazırlayacağıq

IT Sectr 2017-ci ildən startaplar və bizneslər üçün iOS və Android tətbiqləri yaradır. Sizə məsləhət verəcəyik və ən yaxşı həlli təklif edəcəyik.

Layihəni müzakirə et

Həm də oxuyun