Î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ță — 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.
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ă.
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.
Caracterul neregulat al înghețurilor indică faptul că problema este cauzată de factori evenimențiali, nu de suprasolicitare constantă. Să examinăm scenariile tipice.
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ă.
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.
Î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.
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ă.
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.
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.
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:
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")
}
}
}
}
Eliminarea înghețurilor necesită o abordare direcționată pentru fiecare cauză. Nu există o soluție universală — este necesară analiza profilurilor specifice de performanță.
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.
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.
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:
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 se poate face în faza de scriere a codului, respectând principiile de lucru eficient cu memoria și firele.
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.
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.
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.
Întrebări frecvente
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.
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.
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.
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.
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
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.
Citiți și