Îngheață în dezvoltare — ce este, cauze și metode de optimizare

Autor: IT Sectr Publicat: 2026-07-28 Timp de citire: 8 min

Îngheață — este descrierea de către utilizator a situației când aplicația mobilă funcționează lent și instabil: uneori răspunde normal, alteori îngheață brusc câteva secunde. În context tehnic „îngheață” înseamnă o combinație de laguri și micro-înghețuri cauzată de pauze frecvente GC, blocarea firului principal de operații sincrone și structuri de date neoptimale. Conform Android Performance Benchmarking Guide, reducerea timpului de răspuns de la 300 ms la 100 ms crește retenția utilizatorilor cu 25%. Diagnosticarea înghețurilor necesită combinarea profilării CPU și Memory cu analiza frecvenței colectării gunoiului.

Principalele puncte

  • Îngheață — încetinire neregulată a aplicației, alternând cu performanță normală
  • Cauze principale — pauze frecvente GC, operații sincrone în firul UI, volum mare de date în adaptoare fără paginare
  • Diagnosticarea necesită CPU Profiler pentru găsirea blocajelor și Memory Profiler pentru analiza frecvenței și duratei GC
  • Remedierea include implementarea paginării (Paging 3), optimizarea interogărilor SQL prin Room și descărcarea sarcinilor grele în WorkManager
  • Prevenirea — Benchmark Baseline Profiles, compilare AOT, minimizarea alocărilor în căile fierbinți ale codului

Ce înseamnă „îngheață” în dezvoltarea mobilă

Îngheață — un termen informal prin care utilizatorii descriu funcționarea subiectiv lentă a aplicației. Spre deosebire de lag, care se manifestă ca o întârziere constantă, înghețul reprezintă înghețuri neregulate: aplicația poate funcționa perfect câteva secunde, apoi „se gândește” timp de 1–3 secunde.

Caracteristica tehnică a fenomenului

Din punctul de vedere al profilării, îngheață se manifestă ca o serie de cadre pierdute (jank) cu întârzieri de vârf de peste 100 ms. Pe graficul FPS arată ca căderi bruște: 60 → 20 → 55 → 10 cadre pe secundă. Spre deosebire de lag cu FPS uniform scăzut, înghețul are o variabilitate pronunțată.

Percepția utilizatorului

Când aplicația îngheață, utilizatorul nu înțelege logica încetinirilor: ecranul se poate derula lin, apoi brusc se oprește o secundă. Aceasta provoacă frustrare și reduce încrederea în aplicație. Conform Google, 53% dintre utilizatori părăsesc site-ul sau aplicația dacă încărcarea durează mai mult de 3 secunde.

Cauzele încetinirilor bruște în aplicații

Caracterul neregulat al înghețurilor indică faptul că problema este cauzată de factori evenimențiali, nu de suprasolicitare constantă. Să examinăm scenariile tipice.

Pauze GC în timpul alocării obiectelor

Pe Android în mediul ART, colectarea gunoiului oprește toate firele aplicației. Dacă în cod se creează multe obiecte temporare — de exemplu, la fiecare apel onBindViewHolder se creează un nou String prin concatenare — GC pornește mai des. Pauza poate dura 5–50 ms în funcție de dimensiunea heap-ului și generația obiectelor. Utilizatorul simte aceasta ca o „gândire” bruscă.

Interogări SQL sincrone în firul UI

Room pe Android și Core Data pe iOS suportă interogări asincrone, dar dezvoltatorii apelează adesea getValue() sau execută interogarea prin runBlocking pentru simplitate. Un SELECT greu cu join-uri pe un tabel de 10 000 de rânduri poate dura 200–500 ms, blocând complet UI în acest timp.

Decodarea imaginii fără downscale

Încărcarea imaginii de la cameră (12 Mp, 4000x3000 px) fără scalare durează până la 200 ms pentru decodarea în Bitmap. Dacă imaginile sunt încărcate asincron, dar fără un pool de fire cu limitare, pornirea simultană a 5–6 decodări poate supraîncărca CPU, cauzând încetiniri migratoare.

  • Android — concatenarea stringurilor în bucle, crearea de obiecte în căi fierbinți, Bitmap fără inSampleSize
  • iOS — pool-uri autorelease cu un număr mare de obiecte, imageWithContentsOfFile fără scalare, URLSession sincron
  • Cross-platform — parsare JSON în firul UI, încărcarea datelor în firul principal cu așteptarea răspunsului serverului

Cum să diagnostichezi înghețurile pe Android și iOS

Diagnosticarea încetinirilor neregulate este mai dificilă decât diagnosticarea lagurilor constante, deoarece problema poate să nu se reproducă la fiecare pornire. Este necesară colectarea statisticilor pe o perioadă lungă.

Memory Profiler cu înregistrarea evenimentelor GC

Android Studio Memory Profiler arată nu doar utilizarea memoriei, ci și evenimentele GC: frecvența, tipul (Concurrent, Full), durata. Dacă GC apare mai des de 1 dată la 5 secunde în stare de repaus — acesta este un semn de alocare excesivă. Înregistrarea heap dump în momentul înghețului permite să vezi care obiecte ocupă memoria.

Xcode Instruments cu Allocation Tracking

Pe iOS utilizați șablonul Allocations în Instruments pentru urmărirea creării și eliberării obiectelor. Activați generațiile (Generations) — ele permit realizarea de instantanee ale heap-ului între acțiuni și vizualizarea obiectelor care rămân în memorie. Obiectele persistente (Persistent objects) care nu sunt eliberate — sursa acumulării memoriei și a pauzelor ulterioare.

API JankStats pe Android

JankStats — biblioteca Android care colectează metrici ale cadrelor pierdute în timp real. Leagă fiecare jank de scenariul curent (de exemplu, „derularea listei”, „deschiderea ecranului”), ceea ce permite să înțelegem exact la ce acțiune apare înghețul.

Exemplu de integrare JankStats pentru urmărirea înghețurilor pe Android:

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

Metode de eliminare a funcționării lente

Eliminarea înghețurilor necesită o abordare direcționată pentru fiecare cauză. Nu există o soluție universală — este necesară analiza profilurilor specifice de performanță.

Implementarea paginării prin Paging 3

Dacă lista conține 1000+ elemente și toate sunt încărcate odată — acesta este un îngheț garantat. Paging 3 pe Android și NSFetchedResultsController pe iOS încarcă datele pe porțiuni pe măsură ce derulezi. Utilizatorul vede doar primele 10–20 de elemente, restul se încarcă în fundal.

Optimizarea interogărilor SQL și a indexurilor

Room permite profilarea interogărilor prin Inspection Tool în Android Studio: se vede timpul de execuție, numărul de rânduri returnate și planul interogării. Adăugarea de indexuri pe coloanele WHERE și ORDER BY poate reduce timpul interogării de la 300 ms la 5 ms. Pe iOS verificarea similară este efectuată de Core Data Profiler în Instruments.

Delegarea sarcinilor în WorkManager

Sincronizările în fundal, încărcarea fișierelor, procesarea datelor — toate acestea ar trebui executate prin WorkManager (Android) sau Background Tasks (iOS). Dacă sincronizarea pornește în firul UI, aplicația va îngheța pe durata execuției. WorkManager garantează execuția în firul de fundal ținând cont de starea bateriei și a rețelei.

Exemplu de sincronizare în fundal prin WorkManager pe Android:

kotlin
class SyncWorker(context: Context, params: WorkerParameters)
    : CoroutineWorker(context, params) {

    override suspend fun doWork(): Result {
        return try {
            Log.d("Sync", "Sincronizarea datelor în firul de fundal")
            syncData()
            Result.success()
        } catch (e: Exception) {
            Result.retry()
        }
    }
}

Prevenirea înghețurilor în faza de dezvoltare

Prevenirea înghețurilor se poate face în faza de scriere a codului, respectând principiile de lucru eficient cu memoria și firele.

Baseline Profiles pentru compilarea AOT

Baseline Profiles — este lista claselor și metodelor pe care Android le compilează din timp (AOT), nu JIT. Fără profil, fiecare ecran nou se compilează la prima deschidere, provocând o întârziere de 100–500 ms. Pregătiți Baseline Profile pentru ecranele cheie și activați generarea în Gradle prin baseline-profile-gradle-plugin.

Minimizarea alocărilor în căile fierbinți

Hot path — este codul care se execută la fiecare cadru: onBindViewHolder, draw, layoutSubviews. Evitați crearea de obiecte în aceste metode: utilizați un pool de obiecte, StringBuilder în loc de concatenare, cache-uiți stringurile formatate și formatele. Fiecare alocare suplimentară apropie următorul GC.

Profilarea prin Baseline Profiles în CI

Adăugați în pipeline-ul CI lansarea Macrobenchmark cu scenariul de derulare a listei și deschidere a ecranului. Stabiliți un prag: percentila 99 a timpului cadrului nu trebuie să depășească 16 ms. Dacă pragul este depășit — build-ul este respins până la optimizare.

  • Android — Baseline Profiles, Macrobenchmark, JankStats, StrictMode cu penaltyDeath
  • iOS — MetricKit, os_signpost, XCTMetric, Main Thread Checker în schema Debug
  • Abordare generală — profilare regulată, code review cu focus pe alocări în căi fierbinți

Întrebări frecvente

Cu ce se deosebește înghețul de lagul obișnuit?

Lag — este o întârziere constantă (de exemplu, 200 ms pentru fiecare apăsare). Îngheață — neregulat: aplicația funcționează normal, apoi brusc încetinește 1–3 secunde, apoi din nou normal. Cauza — factori evenimențiali precum pauzele GC sau interogările sincrone către baza de date.

Cum să măsurăm frecvența pauzelor GC pe Android?

Utilizați Memory Profiler în Android Studio: fila Memory arată evenimentele GC cu durata. Pentru monitorizarea în producție, conectați Firebase Performance Monitoring cu trace-uri personalizate. Pe iOS activați Malloc Debug și marcați generațiile de alocări în Instruments.

Poate fi cauzat înghețul de interogările de rețea?

Indirect — da. Dacă răspunsul serverului vine cu întârziere, iar UI îl așteaptă sincron, aplicația îngheață. Dacă interogarea este asincronă, dar procesarea răspunsului se face în firul UI — aceasta va cauza de asemenea îngheț. Soluția — procesare asincronă cu corutine și indicatori de progres.

Cum influențează Kotlin Multiplatform performanța?

La utilizarea incorectă KMP poate genera obiecte-wrapper suplimentare pentru interoperabilitate. Pe iOS aceasta crește frecvența alocărilor și, ca urmare, pauzele ARC. Utilizați @ObjCName, optimizați expect/actual și evitați apelurile frecvente ale codului partajat din căile fierbinți ale UI.

Ajută mărirea dimensiunii heap-ului pe Android?

Mărirea heap-ului prin android:largeHeap="true" amână GC, dar nu elimină cauza alocărilor. Când GC totuși pornește, pauza va fi mai lungă pentru că trebuie să parcurgă mai multe obiecte. Soluția — reduceți numărul de alocări, nu extindeți heap-ul.

Concluzii

  • Îngheață — încetinire neregulată a aplicației cauzată de factori evenimențiali (pauze GC, interogări sincrone, decodarea imaginilor)
  • Diagnosticarea necesită Memory Profiler, JankStats pe Android și Allocation Tracking în Instruments pe iOS
  • Cauze principale — pauze frecvente GC, lipsa paginării, interogări SQL neoptimale și procesare sincronă în firul UI
  • Remedierea — Paging 3, WorkManager, optimizarea indexurilor bazei de date, scalarea imaginilor și minimizarea alocărilor
  • Prevenirea — Baseline Profiles, Macrobenchmark, StrictMode, code review cu verificarea căilor fierbinți
  • Instrumente — JankStats, Firebase Performance, MetricKit pentru monitorizarea în producție a înghețurilor
  • Recomandare: implementați lansări regulate de Macrobenchmark în CI cu prag de 16 ms la percentila 99 a cadrelor

Vom dezvolta o aplicație mobilă la cheie

IT Sectr creează aplicații iOS și Android pentru startup-uri și afaceri din 2017. Vă vom consilia și vă vom propune cea mai bună soluție.

Discutați proiectul

Citiți și