Geliştirmede Donmalar — özü, nedenleri ve önleme

Yazar: IT Sectr Yayınlanma: 2026-07-28 Okuma süresi: 9 dk

Donma (takılma), mobil uygulamanın uzun süre boyunca kullanıcının hiçbir eylemine yanıt vermemesi durumudur. Lag (yavaşlama) ve glitch (hatalı davranış)tan farklı olarak donma, UI'yı tamamen bloke eder: dokunuşlar işlenmez, animasyon durur, ekran “donar”. Nedeni, ana iş parçacığının senkron bir işlem tarafından bloke edilmesi, çok iş parçacıklı kodda deadlock veya anormal derecede uzun çöp toplamadır. Apple Main Thread Checker Dokümantasyonu'na göre, iOS crash raporlarının %40'ından fazlası ana iş parçacığı blokajıyla ilgilidir. Android'de benzer bir durum ANR'ye — sistem diyaloğu “Uygulama yanıt vermiyor” — yol açar.

Ana Hatlar

  • Donma — uzun süre (saniyeler ve onlarca saniye) boyunca UI'nın tamamen bloke olması, lag ve glitch'ten farklıdır
  • Temel nedenler — G/Ç tarafından ana iş parçacığı blokajı, iş parçacıkları arasında deadlock, sonsuz döngü ve uzun GC ile bellek sızıntısı
  • Teşhis, iOS'ta Main Thread Checker, Android'de ANR günlükleri /data/anr/traces.txt ve iş parçacığı dökümü analizini içerir
  • Giderme — potansiyel olarak uzun tüm işlemleri arka plan iş parçacıklarına aktarma, Structured Concurrency kullanma ve UI iş parçacığında synchronized'dan kaçınma
  • Önleme — StrictMode, Debug şemasında Main Thread Checker, deadlock için statik analiz ve yanıt süresini ölçen periyodik testler

Mobil Geliştirmede Donma Nedir

Donma (takılma), mobil uygulamada uygulamanın birkaç saniye veya daha uzun süre giriş olaylarını işlemeyi ve arayüzü güncellemeyi durdurması durumudur. Teknik olarak bu, ana iş parçacığının bloke olduğu ve bir sonraki çalıştırma döngüsü yinelemesini gerçekleştiremediği anlamına gelir.

Donma, Lag ve ANR Arasındaki Fark

Lag, kullanıcının yavaşlama fark ettiği ancak uygulamanın çalışmaya devam ettiği 500 ms'ye kadar olan gecikmedir. Donma 1 saniyeden onlarca saniyeye kadar sürer. Android'de ANR, 5 saniyeden uzun süren ve sistem tarafından tespit edilen özel bir donma durumudur. Her donma ANR'ye yol açmaz, ancak her ANR sistem tarafından belgelenmiş bir donmadır.

Donmaların Sonuçları

Android'te, 5 saniyeden uzun süren donma, uygulamayı kapatmayı öneren bir ANR diyaloğu tetikler. iOS'ta, sistemin bir watchdog'u vardır — uygulama 10–20 saniye boyunca olaylara yanıt vermezse, Watchdog işlemi 0x8badf00d (ate bad food) koduyla sonlandırır. Kullanıcı yalnızca uygulamanın aniden ana ekrana kapanmasını görür.

Android ve iOS'ta Donma Nedenleri

100 ms'den uzun süren ve ana iş parçacığında başlatılan herhangi bir işlem potansiyel olarak donmaya neden olabilir. Blokajların ana kaynaklarına bakalım.

UI İş Parçacığında Senkron G/Ç

Büyük bir dosya okumak, eşzamansızlık olmadan ağ isteği, senkron apply yöntemi ve ardından commit ile SharedPreferences'a veri kaydetmek — tüm bu işlemler ana iş parçacığını bloke eder. Android'te, 10 MB'lık bir dosyayı senkron okumak, flash bellek hızına bağlı olarak 200–500 ms sürebilir. iOS'ta, completionHandler olmadan senkron URLSession yüklemesi, sunucu yanıt süresi boyunca UI'yı bloke eder.

Çok İş Parçacıklı Kodda Deadlock

İki iş parçacığı birbirinin tuttuğu kaynakları beklediğinde deadlock oluşur. Mobil uygulamalarda tipik senaryo, A iş parçacığının Lock1'i kilitleyip Lock2'yi beklemesi, B iş parçacığının ise Lock2'yi kilitleyip Lock1'i beklemesidir. Her iki iş parçacığı da sonsuza kadar donar. Bunlardan biri ana iş parçacığıysa, uygulama tamamen donar.

Sonsuz Döngü veya Özyineleme

Bir mantık hatası — örneğin, çıkış koşulu olmayan while(true) veya temel durumu olmayan özyineleme — ana iş parçacığında sonsuz yürütmeye yol açar. Android bunu 5 saniye sonra ANR ile tespit eder, iOS — sonsuz tekrarlanan çağrı yığınını yakalayan Stackshot ile tespit eder.

  • Android — Kapatılmayan Cursor, enqueue() yerine execute() ile senkron istek, UI iş parçacığında FileInputStream.read()
  • iOS — performSelectorOnMainThread:withObject:waitUntilDone:YES, NSURLConnection sendSynchronousRequest başlatma, dataWithContentsOfURL ile resim yükleme
  • Platformlar arası — Ayrılmış isolate olmadan Flutter compute, senkron React Native NativeModule

Donmalar Nasıl Teşhis Edilir

Donma teşhisi, blokaj anında tüm iş parçacıklarının durumunu yakalayabilen araçlar gerektirir.

Android'de ANR Günlükleri

Her ANR'de, Android sistemi her uygulama iş parçacığının yığın dökümünü içeren bir dosya /data/anr/traces.txt kaydeder. Bu dosyayı analiz etmek ana teşhis yöntemidir: main iş parçacığını bulun ve hangi yöntemde durduğunu görün. Yığın Thread.sleep, InputStream.read veya Lock.lock ile bitiyorsa — neden bulunmuştur.

iOS'ta Stackshot

Xcode, uygulama donduğunda (SIGSTOP sinyali) bir Stackshot — tüm iş parçacığı yığınlarının anlık görüntüsü — alabilir. Şemada “Logging” → “Include Stackshot Logs” seçeneğini etkinleştirin. 0x8badf00d koduyla çökme durumunda, Devices & Simulators'dan crash günlüğünü çıkarın ve sıkışmış yığınla com.apple.main-thread'i bulun.

Xcode'da Main Thread Checker

Main Thread Checker, uygulama çalışırken arka plan iş parçacıklarından UIKit çağrılarını otomatik olarak algılar. Şemada etkinleştirin (Diagnostics → Main Thread Checker). Her uyarı, özellikle bir ağ isteği completionHandler closure'ında meydana gelirse, donmanın potansiyel bir nedenidir.

Android'de StrictMode ile blokaj tespiti örneği:

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 Blokajlarını Giderme Yöntemleri

Donmaları giderme, potansiyel olarak uzun tüm işlemleri arka plan iş parçacıklarına taşımakla başlar. Her platform için belirli tekniklere bakalım.

Coroutine ile Yapılandırılmış Eşzamanlılık

Kotlin Coroutines viewModelScope.launch(Dispatchers.IO) ile ağ işlemlerinin veya veritabanı okumalarının arka plan iş parçacığında yürütülmesini sağlar. Dispatchers.Main yalnızca UI güncellemeleri için kullanılır. Önemli: tüm suspend işlevleri yapılandırılmış olmalıdır — alt coroutine'ler üst iptal edildiğinde iptal edilir, iş parçacığı sızıntılarını önler.

iOS'ta Zaman Uyumsuz Kuyruklar

Grand Central Dispatch arka plan görevleri için DispatchQueue.global(qos: .userInitiated) ve UI güncellemeleri için DispatchQueue.main.async ile standart desendir. Ana kuyrukta sync()'ten kaçının — bu garantili bir deadlock'tur. MainActor aracılığıyla ana iş parçacığına otomatik dönüşle daha okunabilir zaman uyumsuz kod için async/await (Swift 5.5+) kullanın.

UI İş Parçacığında synchronized'dan Kaçınma

Ana iş parçacığında Kotlin'de synchronized blokları ve Swift'te @synchronized tehlikelidir: başka bir iş parçacığı bu kilidi zaten almışsa, ana iş parçacığı beklerken donar. Kilitler yerine atomik türler (AtomicInteger, Swift'te atomik özellikler) veya sıralı kuyruklar kullanın.

Android'de coroutine ile zaman uyumsuz veri yükleme örneği:

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

Geliştirme Aşamasında Donmaları Önleme

Araçlar, mimari ilkeler ve kod inceleme süreçlerinin bir kombinasyonu, donmaları sistematik olarak önlemeye yardımcı olur.

penaltyDeath ile StrictMode

İş parçacığı politikaları için StrictMode'u penaltyDeath ile yapılandırın — bu, ana iş parçacığında bir ağ çağrısı veya disk G/Ç tespit edildiğinde uygulamanın anında çökmesine neden olur. Geliştirici sorunu görmezden gelemez. Üretim yapılarında, çökme olmadan istatistik toplamak için penaltyLog kullanın.

Debug Şemasında Main Thread Checker

iOS'ta, Debug şemasında Main Thread Checker'ı etkinleştirin ve CI'yi bu seçenekle testleri çalıştıracak şekilde yapılandırın. Bir test, arka plan iş parçacığından bir UIKit çağrısı içeriyorsa — başarısız olmalıdır. TestFlight'a göndermeden önce sorunu belirlemenin tek güvenilir yolu budur.

Çoklu İş Parçacığı Denetimiyle Eş İncelemesi

Kod inceleme sürecine zorunlu bir madde ekleyin: herhangi bir ağ çağrısı, dosya işlemi, veritabanı erişimi veya ağır hesaplamanın arka plan iş parçacığında çalıştığını kontrol edin. Deadlock, statik analizörlerle tespit edilebilir: Facebook'tan Infer ve Xcode'dan Thread Safety Checker, çalışma zamanından önce potansiyel kilitleri bulur.

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

Sıkça Sorulan Sorular

Donma ve ANR arasındaki fark nedir?

ANR (Application Not Responding), ana iş parçacığı 5 saniyeden fazla donduğunda görünen bir Android sistem bildirimidir. Donma daha geniş bir kavramdır: herhangi bir süredeki herhangi bir UI blokajı. iOS'ta ANR yoktur, ancak 10–20 saniye zaman aşımlı bir Watchdog vardır.

Android'de traces.txt nasıl okunur?

Dosya /data/anr/traces.txt konumundadır. Erişim için root erişimi veya adb shell gerekir: root yetkileriyle adb shell cat /data/anr/traces.txt \> traces.txt komutunu çalıştırın. Yığında “main” iş parçacığını bulun — son çağrılan yöntem blokajın nedenini gösterir.

Uygulama iOS'ta neden donar ama çökmez?

Donma 10 saniyeden az sürerse, Watchdog tetiklenmez ve uygulama bloke eden işlem tamamlanana kadar “takılı kalır”. Kullanıcı çökme görmez ancak hayal kırıklığı yaşar. Bu tür durumları tespit etmek için, özel yürütme süresi izleriyle MetricKit kullanın.

Uygulama donmalara karşı nasıl test edilir?

Ekranın 1 saniyeden kısa sürede açıldığını kontrol eden UI testleri kullanın. Dokunma ile sonraki ekranın görünmesi arasındaki süre ölçümünü CI'ya ekleyin. Android'te, zaman uyumsuz işlemleri beklemek için IdlingResource ile Espresso kullanın. iOS'ta, yükleme süresini kontrol etmek için XCTWaiter ile XCTest kullanın.

SwiftUI donmalara neden olabilir mi?

SwiftUI kendisi donmalara neden olmaz, ancak body özelliğindeki karmaşık hesaplamalar neden olur. Ağır işlemler nedeniyle body hesaplaması 500 ms sürerse, UI donar. Çözüm, hesaplamaları Task.detached'a aktarmak ve @State'i ana aktörde zaman uyumsuz olarak güncellemektir.

Özet

  • Donma — ana iş parçacığı blokajı, deadlock veya sonsuz döngü nedeniyle saniyeler ila onlarca saniye süren tam UI blokajı
  • Teşhis — Android'de /data/anr/traces.txt, iOS'ta Stackshot ve Main Thread Checker
  • Temel nedenler — senkron G/Ç, iş parçacıkları arasında deadlock, sonsuz özyineleme, uzun GC
  • Giderme — doğru dağıtıcılarla coroutine'ler, MainActor ile async/await, tüm G/Ç işlemlerini arka plan iş parçacıklarına aktarma
  • Önleme — penaltyDeath ile StrictMode, Main Thread Checker, deadlock için statik analiz (Infer, TSAN)
  • Android'te donma > 5 sn = ANR; iOS'ta > 10–20 sn = Watchdog çökmesi (0x8badf00d)
  • Öneri: Debug şemasında Thread Sanitizer'ı etkinleştirin ve veri yarışlarını ve deadlock'ları tespit etmek için CI'yi TSAN ile testleri çalıştıracak şekilde yapılandırın

Anahtar teslim bir mobil uygulama geliştireceğiz

IT Sectr, 2017'den beri girişimler ve işletmeler için iOS ve Android uygulamaları oluşturmaktadır. Size danışmanlık yapacak ve en iyi çözümü önereceğiz.

Projeyi tartış

Ayrıca okuyun