Einfrierungen in der Entwicklung — Wesen, Ursachen und Vorbeugung

Autor: IT Sectr Veröffentlicht: 2026-07-28 Lesezeit: 9 Min.

Einfrieren (Hängenbleiben) ist ein Zustand, in dem eine mobile App für längere Zeit auf keine Benutzeraktionen mehr reagiert. Im Gegensatz zu Lags (Verlangsamung) und Glitches (fehlerhaftem Verhalten) blockiert das Einfrieren die UI vollständig: Berührungen werden nicht verarbeitet, Animationen stoppen, der Bildschirm „gefriert“. Die Ursache ist die Blockierung des Hauptthreads durch eine synchrone Operation, ein Deadlock in Multithread-Code oder eine ungewöhnlich lange Garbage Collection. Laut Apple Main Thread Checker Dokumentation stehen mehr als 40 % der iOS-Crashberichte im Zusammenhang mit der Blockierung des Hauptthreads. Unter Android führt eine ähnliche Situation zu ANR — dem Systemdialog „App antwortet nicht“.

Wichtige Punkte

  • Einfrieren — vollständige UI-Blockierung für längere Zeit (Sekunden bis mehrere Sekunden), unterscheidet sich von Lags und Glitches
  • Hauptursachen — Hauptthread-Blockierung durch E/A, Deadlock zwischen Threads, Endlosschleife und Speicherleck mit langer GC
  • Diagnose umfasst Main Thread Checker auf iOS, ANR-Protokolle /data/anr/traces.txt auf Android und Thread-Dump-Analyse
  • Beseitigung — Auslagerung aller potenziell langen Operationen in Hintergrundthreads, Verwendung von Structured Concurrency und Vermeidung von synchronized im UI-Thread
  • Vorbeugung — StrictMode, Main Thread Checker im Debug-Schema, statische Analyse auf Deadlock und regelmäßige Tests zur Messung der Reaktionszeit

Was ist ein Einfrieren in der mobilen Entwicklung

Einfrieren (Hängenbleiben) in einer mobilen App ist ein Zustand, in dem die App für mehrere Sekunden oder länger keine Eingabeereignisse mehr verarbeitet und die Oberfläche nicht aktualisiert. Technisch bedeutet dies, dass der Hauptthread blockiert ist und die nächste Run-Loop- Iteration nicht ausführen kann.

Unterschied zwischen Einfrieren, Lag und ANR

Ein Lag ist eine Verzögerung von bis zu 500 ms, bei der der Benutzer eine Verlangsamung bemerkt, die App aber weiterläuft. Einfrieren dauert von 1 Sekunde bis zu mehreren Sekunden. ANR auf Android ist ein Sonderfall eines Einfrierens, das länger als 5 Sekunden dauerte und vom System erkannt wurde. Nicht jedes Einfrieren führt zu ANR, aber jedes ANR ist ein systemdokumentiertes Einfrieren.

Folgen von Einfrierungen

Unter Android löst ein Einfrieren von mehr als 5 Sekunden einen ANR-Dialog aus, der zum Schließen der App auffordert. Unter iOS verfügt das System über einen Watchdog — wenn die App 10–20 Sekunden lang nicht auf Ereignisse reagiert, beendet der Watchdog den Prozess mit dem Code 0x8badf00d (ate bad food). Der Benutzer sieht nur, wie die App plötzlich zum Startbildschirm geschlossen wird.

Ursachen von Einfrierungen auf Android und iOS

Jeder Vorgang, der länger als 100 ms dauert und im Hauptthread ausgeführt wird, kann potenziell ein Einfrieren verursachen. Sehen wir uns die Hauptquellen von Blockaden an.

Synchroner E/A im UI-Thread

Lesen einer großen Datei, eine Netzwerkanfrage ohne Asynchronität, Speichern von Daten in SharedPreferences mit der synchronen Methode apply gefolgt von commit — all diese Operationen blockieren den Hauptthread. Unter Android kann das synchrone Lesen einer 10 MB großen Datei je nach Flash-Speichergeschwindigkeit 200–500 ms dauern. Unter iOS blockiert ein synchroner URLSession-Ladevorgang ohne completionHandler die UI für die Dauer der Serverantwort.

Deadlock in Multithread-Code

Wenn zwei Threads auf Ressourcen warten, die vom jeweils anderen gehalten werden, entsteht ein Deadlock. In mobilen Apps ist ein typisches Szenario: Thread A sperrt Lock1 und wartet auf Lock2, während Thread B Lock2 sperrt und auf Lock1 wartet. Beide Threads frieren für immer ein. Wenn einer davon der Hauptthread ist, friert die App vollständig ein.

Endlosschleife oder Rekursion

Ein Logikfehler — zum Beispiel while(true) ohne Ausstiegsbedingung oder Rekursion ohne Basisfall — führt zu einer unendlichen Ausführung im Hauptthread. Android erkennt dies nach 5 Sekunden über ANR, iOS — über Stackshot, das einen sich unendlich wiederholenden Aufrufstapel erfasst.

  • Android — Cursor ohne Schließen, synchrone Anfrage über execute() statt enqueue(), FileInputStream.read() im UI-Thread
  • iOS — performSelectorOnMainThread:withObject:waitUntilDone:YES, Starten von NSURLConnection sendSynchronousRequest, Laden eines Bildes mit dataWithContentsOfURL
  • Plattformübergreifend — Flutter compute ohne dediziertes Isolate, synchrones React Native NativeModule

Wie man Einfrierungen diagnostiziert

Die Diagnose von Einfrierungen erfordert Werkzeuge, die den Zustand aller Threads im Moment der Blockierung erfassen können.

ANR-Protokolle unter Android

Bei jedem ANR speichert das Android-System eine Datei /data/anr/traces.txt mit einem Stapeldump jedes App-Threads. Die Analyse dieser Datei ist die wichtigste Diagnosemethode: Finden Sie den main-Thread und sehen Sie, bei welcher Methode er gestoppt hat. Wenn der Stack mit Thread.sleep, InputStream.read oder Lock.lock endet — ist die Ursache gefunden.

Stackshot unter iOS

Xcode kann beim Einfrieren der App (SIGSTOP-Signal) einen Stackshot — eine Momentaufnahme aller Thread-Stacks — erstellen. Aktivieren Sie „Logging“ → „Include Stackshot Logs“ im Schema. Bei einem Absturz mit Code 0x8badf00d extrahieren Sie das Crash-Protokoll aus Devices & Simulators und suchen Sie den com.apple.main-thread mit dem feststeckenden Stack.

Main Thread Checker in Xcode

Main Thread Checker erkennt automatisch UIKit-Aufrufe aus Hintergrundthreads während der Ausführung der App. Aktivieren Sie es im Schema (Diagnostics → Main Thread Checker). Jede Warnung ist eine potenzielle Ursache für ein Einfrieren, insbesondere wenn sie in einem completionHandler-Closure einer Netzwerkanfrage auftritt.

Beispiel für die Erkennung von Blockaden via StrictMode unter Android:

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

Methoden zur Beseitigung von UI-Blockaden

Die Beseitigung von Einfrierungen beginnt damit, alle potenziell langen Operationen in Hintergrundthreads zu verschieben. Sehen wir uns spezifische Techniken für jede Plattform an.

Strukturierte Nebenläufigkeit mit Coroutinen

Kotlin Coroutines mit viewModelScope.launch(Dispatchers.IO) stellen sicher, dass Netzwerkoperationen oder Datenbanklesevorgänge in einem Hintergrundthread ausgeführt werden. Dispatchers.Main wird nur für UI-Updates verwendet. Wichtig: Alle suspend-Funktionen müssen strukturiert sein — untergeordnete Coroutinen werden bei Abbruch der übergeordneten abgebrochen, wodurch Thread-Leaks verhindert werden.

Asynchrone Warteschlangen unter iOS

Grand Central Dispatch mit DispatchQueue.global(qos: .userInitiated) für Hintergrundaufgaben und DispatchQueue.main.async für UI-Updates ist das Standardmuster. Vermeiden Sie sync() in der Hauptwarteschlange — dies ist ein garantierter Deadlock. Verwenden Sie async/await (Swift 5.5+) für besser lesbaren asynchronen Code mit automatischer Rückkehr zum Hauptthread über MainActor.

Vermeidung von synchronized im UI-Thread

Synchronized-Blöcke in Kotlin und @synchronized in Swift im Hauptthread sind gefährlich: Wenn ein anderer Thread diese Sperre bereits erworben hat, friert der Hauptthread wartend ein. Verwenden Sie atomare Typen (AtomicInteger, atomare Eigenschaften in Swift) oder serielle Warteschlangen anstelle von Sperren.

Beispiel für asynchrones Laden von Daten mit Coroutinen unter Android:

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

Vorbeugung von Einfrierungen in der Entwicklungsphase

Eine Kombination aus Werkzeugen, Architekturprinzipien und Code-Review-Prozessen hilft, Einfrierungen systematisch zu verhindern.

StrictMode mit penaltyDeath

Konfigurieren Sie StrictMode mit penaltyDeath für Thread-Richtlinien — dies führt zu einem sofortigen App-Absturz, wenn ein Netzwerkaufruf oder Festplatten-E/A im Hauptthread erkannt wird. Der Entwickler kann das Problem nicht ignorieren. Verwenden Sie in Produktions-Builds penaltyLog, um Statistiken ohne Abstürze zu sammeln.

Main Thread Checker im Debug-Schema

Aktivieren Sie unter iOS Main Thread Checker im Debug-Schema und konfigurieren Sie CI, um Tests mit dieser Option auszuführen. Wenn ein Test einen UIKit-Aufruf aus einem Hintergrundthread enthält — sollte er fehlschlagen. Dies ist der einzige zuverlässige Weg, das Problem vor dem Senden an TestFlight zu identifizieren.

Peer-Review mit Multithreading-Prüfung

Fügen Sie dem Code-Review-Prozess einen obligatorischen Punkt hinzu: Überprüfen Sie, ob jeder Netzwerkaufruf, Dateivorgang, Datenbankzugriff oder schwere Berechnung in einem Hintergrundthread ausgeführt wird. Deadlock kann mit statischen Analysewerkzeugen erkannt werden: Infer von Facebook und Thread Safety Checker von Xcode finden potenzielle Sperren vor der Laufzeit.

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

Häufig gestellte Fragen

Was ist der Unterschied zwischen Einfrieren und ANR?

ANR (Application Not Responding) ist eine Android-Systembenachrichtigung, die erscheint, wenn der Hauptthread länger als 5 Sekunden eingefroren ist. Einfrieren ist ein breiterer Begriff: jede UI-Blockierung beliebiger Dauer. iOS hat kein ANR, aber einen Watchdog mit einem Timeout von 10–20 Sekunden.

Wie liest man traces.txt auf Android?

Die Datei befindet sich unter /data/anr/traces.txt. Der Zugriff erfordert Root-Zugriff oder adb shell: Führen Sie adb shell cat /data/anr/traces.txt \> traces.txt mit Root-Rechten aus. Suchen Sie im Stack den Thread „main“ — die zuletzt aufgerufene Methode gibt die Ursache der Blockierung an.

Warum friert die App unter iOS ein, stürzt aber nicht ab?

Wenn das Einfrieren weniger als 10 Sekunden dauert, löst der Watchdog nicht aus, und die App „hängt“ einfach, bis die blockierende Operation abgeschlossen ist. Der Benutzer sieht keinen Absturz, erlebt aber Frustration. Verwenden Sie MetricKit mit benutzerdefinierten Ausführungszeit-Traces, um solche Fälle zu erkennen.

Wie testet man eine App auf Einfrierungen?

Verwenden Sie UI-Tests mit der Überprüfung, dass der Bildschirm in < 1 Sekunde geöffnet wird. Fügen Sie die Zeitmessung zwischen Tippen und Erscheinen des nächsten Bildschirms zum CI hinzu. Verwenden Sie unter Android Espresso mit IdlingResource, um auf asynchrone Operationen zu warten. Verwenden Sie unter iOS XCTest mit XCTWaiter, um die Ladezeit zu überprüfen.

Kann SwiftUI Einfrierungen verursachen?

SwiftUI selbst verursacht keine Einfrierungen, aber komplexe Berechnungen in der body-Eigenschaft schon. Wenn die Berechnung von body aufgrund schwerer Operationen 500 ms dauert, friert die UI ein. Die Lösung besteht darin, Berechnungen in Task.detached auszulagern und @State asynchron auf dem Hauptakteur zu aktualisieren.

Zusammenfassung

  • Einfrieren — vollständige UI-Blockierung für Sekunden bis mehrere Sekunden, verursacht durch Hauptthread-Blockierung, Deadlock oder Endlosschleife
  • Diagnose — /data/anr/traces.txt auf Android, Stackshot und Main Thread Checker auf iOS
  • Hauptursachen — synchrone E/A, Deadlock zwischen Threads, Endlosrekursion, lange GC
  • Beseitigung — Coroutinen mit korrekten Dispatchern, async/await mit MainActor, Auslagerung aller E/A-Operationen in Hintergrundthreads
  • Vorbeugung — StrictMode mit penaltyDeath, Main Thread Checker, statische Analyse auf Deadlock (Infer, TSAN)
  • Auf Android Einfrieren > 5 s = ANR; auf iOS > 10–20 s = Watchdog-Absturz (0x8badf00d)
  • Empfehlung: aktivieren Sie Thread Sanitizer im Debug-Schema und konfigurieren Sie CI, um Tests mit TSAN auszuführen, um Datenwettläufe und Deadlocks zu erkennen

Wir entwickeln eine mobile Applikation schlüsselfertig

IT Sectr entwickelt seit 2017 iOS- und Android-Apps für Startups und Unternehmen. Wir beraten Sie und schlagen die beste Lösung vor.

Projekt besprechen

Lesen Sie auch