Prestanda inom mobil utveckling: vad det är, vilka mätvärden och hur man förbättrar

Författare: IT Sectr Publicerad: 2026-03-25 Lästid: 12 min

En långsam app är den främsta anledningen till att användare tar bort program. Millisekunders fördröjning vid start eller vid rullning av en lista minskar retention med tiotals procent. Prestanda (performance) är inte bara hastighet, utan också stabilitet: frånvaro av ANR, krascher och minnesläckor. Den här artikeln täcker alla aspekter av prestanda: från minneshantering (GC, ARC) till profilering med verktyg. Läs mer i den officiella Android Performance-guiden.

Huvudpunkter

  • ANR och krasch — användarupplevelsens främsta fiender; förhindras med bakgrundstrådar
  • Minnesläcka och Retain Cycle leder till OOM-krascher; löses med svaga referenser och verktyg
  • GC (Android) och ARC (iOS) — modeller för minneshantering; förståelse för deras funktion är kritisk
  • Profilering (Instruments, Android Profiler, LeakCanary) — en obligatorisk utvecklingsfas
  • Cold Start — det viktigaste startmåttet; optimering av Application.onCreate och lat initialisering
  • Appstorlek — använd App Bundle, R8, VectorDrawable och WebP för att minska storleken

Varför är appen långsam?

Appens prestanda är direkt kopplad till jank — en märkbar fördröjning mellan användaråtgärd och UI-svar. Huvudorsaker: blockering av huvudtråden (tunga operationer på UI-tråden), frekventa omritningar av layout (overdraw), minnesläckor (frekvent GC), icke-optimala algoritmer (O(n²) på stora datamängder). Bildhastighet (FPS) — antal bildrutor per sekund. För en bekväm upplevelse krävs stabila 60 FPS (Android) eller 120 FPS (iPhone Pro, iPad Pro). VSync synkroniserar renderingen med skärmens uppdateringsfrekvens.

Jank uppstår när rendering av en enskild bildruta överstiger 16,6 ms (för 60 FPS) eller 8,3 ms (för 120 FPS). GPU-profilering (Profile GPU Rendering på Android, Core Animation på iOS) visar vilka renderingsstadier som tar mest tid. Huvudstadier: Layout (placering av element), Draw (ritning), Display (överföring till bildrutebuffert). Det vanligaste problemet är layoutinflation i XML, särskilt vid användning av komplexa nästlade ConstraintLayout.

Time-to-Interactive (TTI) — tiden det tar för appen att bli helt redo för interaktion. TTI inkluderar Cold Start, databelastning och biblioteksinitiering. Google rekommenderar TTI under 5 sekunder, Apple — under 2 sekunder för huvudskärmar. Lat laddning — teknik för fördröjd laddning av innehåll och bibliotek, avgörande för att förbättra TTI. På IT Sectr använder vi lat initialisering som standard i alla projekt.

ANR och krasch

ANR och krasch är de främsta fienderna till mobil app-prestanda. ANR (Application Not Responding) — dialogruta på Android som visas om huvudtråden är blockerad i mer än 5 sekunder. Orsaker: synkrona nätverksförfrågningar på UI-tråden, databasarbete utan korutiner, avkodning av stor bitmapp utan nedsampling, deadlock på huvudtråden. ANR-anropsstacken sparas i /data/anr/traces.txt och gör det möjligt att fastställa den exakta blockeringsplatsen.

Krasch — oväntad avslutning av appen. På Android — ett Exception (Java/Kotlin) eller Signal (inbyggd kod). På iOS — NSException eller signal (EXC_BAD_ACCESS — åtkomst till frigjort minne). Kraschrapporteringsverktyg: Firebase Crashlytics, Sentry, BugSnag. De samlar in stacktrace, enhetsdata och reproduktionssteg. Stack Overflow — spill av anropsstacken på grund av oändlig rekursion. OutOfMemoryError — när heapen är full.

StrictMode — Android-verktyg för att upptäcka trådsäkerhetsöverträdelser. Tillåter att regler ställs in: ThreadPolicy (förbjud disk/nätverk på huvudtråden), VmPolicy (upptäck läckor av Activity, SQLite, CloseGuard). StrictMode bör aktiveras endast i debug-byggen — i release ska det inte fungera. På iOS är motsvarigheten Main Thread Checker (Xcode), som automatiskt upptäcker UIKit-anrop som inte är på huvudtråden.

Minneshantering (GC, ARC, Retain Cycle)

Minnesläcka

En minnesläcka (Memory Leak) är en situation där ett objekt finns kvar i minnet trots att appen inte längre använder det. Detta minskar direkt appens prestanda. På Android kan GC (Garbage Collection) inte samla in ett objekt om det finns en stark referens till det. Typiska orsaker: statiska referenser till Activity, inte avbokade callbacks/observatörer, inre klasser med implicit referens till den yttre klassen, Handler med inte rensade meddelanden. LeakCanary — bibliotek för automatisk läckdetektering.

Retain Cycle (Retentionscykel)

ARC (Automatic Reference Counting) — modell för minneshantering på iOS. Varje objekt har en referensräknare (retain count). När räknaren når noll frigörs minnet. En Retain Cycle uppstår när två objekt håller starka referenser till varandra (A → B och B → A). ARC kommer aldrig att nollställa räknarna. Lösning: svaga (weak) eller ägarlösa (unowned) referenser. Weak nollställs automatiskt (blir nil) när objektet frigörs. Unowned nollställs inte men garanterar att objektet lever.

GC vs ARC

GC (Garbage Collection) fungerar på Android (Java/Kotlin). GC pausar periodvis exekveringen (Stop-the-World-paus) för att hitta och frigöra oåtkomliga objekt. GC-utlösare: när heapen fylls till en viss procent. ARC fungerar på iOS (Swift/Objective-C) och har inga pauser — räknarna uppdateras atomärt vid varje tilldelning. ARC är mer förutsägbart, men kan ackumulera överdrivna retain/release-operationer vid hög tilldelningsfrekvens.

Svag referens (Weak Reference) och stark referens (Strong Reference) — referenstypen avgör om GC/ARC kan frigöra objektet. Strong Reference — objektet kommer inte att samlas in så länge denna referens finns. Weak Reference — GC/ARC kan samla in objektet; den svaga referensen blir nil (i Swift/Java WeakReference). Unowned Reference (Swift) — nollställs inte vid frigivning; åtkomst till den efter objektets död orsakar en krasch. På Android används java.lang.ref.WeakReference för svaga referenser.

Exempel på läckdetektering på Android med LeakCanary:

kotlin
// Утечка: анонимный класс держит ссылку на Activity
class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        val handler = object : Handler(Looper.getMainLooper()) {
            override fun handleMessage(msg: Message) {
                // Используем `this@MainActivity`, сохраняя ссылку на Activity
                Log.d("TAG", "Handler received message")
            }
        }
        handler.sendEmptyMessageDelayed(0, 60000)
    }
}

// Исправление: статический Handler + WeakReference
class SafeHandler(activity: MainActivity) : Handler() {
    private val weakActivity =
        WeakReference(activity)

    override fun handleMessage(msg: Message) {
        weakActivity.get() ?: return
        Log.d("TAG", "Handler received message")
    }
}

Profilering (Instruments, Android Profiler)

Profilering är processen att mäta appens prestanda: CPU, minne, nätverk, energiförbrukning. Utan profilering är blind optimering värdelös — du vet inte vilken del av koden som faktiskt är långsam.

Verktyg Plattform Mäter När ska användas
Instruments (Time Profiler)iOSCPU, funktionsanrop, exekveringstidAlgoritmoptimering, sökning efter flaskhalsar
Instruments (Allocations)iOSMinne, antal objekt, retain countsSökning efter läckor och överdriven minnesförbrukning
Instruments (Leaks)iOSRetain cycles, minnesläckorRegelbunden kontroll före release
Android Profiler (CPU)AndroidCPU-användning, trådaktivitet, tracesSökning efter blockeringar av huvudtråden
Android Profiler (Memory)AndroidHeap dump, allokeringsspårningSökning efter läckor, objektanalys
Android Profiler (Network)AndroidTrafik, hastighet, förfrågningstiderOptimering av nätverksanrop
LeakCanaryAndroidAutomatisk detektering av minnesläckorI alla utvecklingsstadier
StrictModeAndroidDisk/nätverk på huvudtråden, läckorDebug-bygge
Traceview / SystraceAndroidMetodspårning, systemhändelserDjupgående latensanalys

Instruments (Xcode) — det mest kraftfulla verktyget för iOS. Time Profiler visar vilka funktioner som förbrukar mest CPU. Allocations spårar skapande och frigöring av objekt. Leaks hittar automatiskt retain cycles. Profileringssteg: (1) starta Instruments; (2) välj mall (Time Profiler för CPU); (3) kör det problematiska scenariot; (4) analysera anropsstacken — den bredaste kolumnen är den "hetaste" funktionen.

Android Profiler är inbyggt i Android Studio (View → Tool Windows → Profiler). CPU Profiler visar belastningen på varje tråd. Memory Profiler — heap dump och allokeringsspårning. Network Profiler — alla HTTP-förfrågningar med tider. Energy Profiler — energiförbrukning: WakeLock, Location, Network. För detaljerad spårning används Systrace (Android 10+) eller Perfetto — systemspårning med mikrosekunders precision.

Appstart (Cold/Warm/Hot Start)

Appstart är en av de viktigaste prestandaindikatorerna. Det delas in i tre typer: Cold Start — appen startas från början: processen skapas, Application.onCreate (Android) / AppDelegate.applicationDidFinishLaunching (iOS), klassladdning, biblioteksinitiering. Warm Start — processen finns, men Activity/ViewController är förstört (t.ex. vid skärmrotation eller återkomst från minne). Hot Start — Activity/ViewController finns i minnet, appen visas bara (växling från en annan app).

Cold Start är det viktigaste mätvärdet. På Android inkluderar det: (1) launch Activity — XML-laddning, View-initiering; (2) första bildrutan — tid till första rendering. Google rekommenderar: launch Activity < 200 ms, första bildrutan < 500 ms, TTI < 5 sekunder. Cold Start-optimering: minska Application.onCreate (korutiner för lat initialisering), använd SplashScreen API (Android 12+), skjut upp biblioteksinitiering (WorkManager, DI), ta bort onödiga ContentProviders.

På iOS inkluderar Cold Start: laddning av Mach-O binärfil, dyld (dynamisk länkare), initiering av Objective-C runtime, application delegate, första kontrollern. Chrome Custom Tabs (Android) och Universal Links (iOS) — tekniker för att snabbt öppna externt innehåll i appen utan full Cold Start. Det rekommenderas att testa Cold Start på verkliga medelklassenheter.

Storleksoptimering

Appstorlek är en prestandafaktor för installation och uppdateringar. Det påverkar konvertering: varje 10 MB minskar konverteringen med 1%. Google Play rekommenderar APK-storlek under 150 MB; App Store — under 200 MB (mobilnät — 100 MB). Huvudsakliga optimeringsmetoder: bildkomprimering (WebP istället för PNG sparar 25-35%), vektorisering (VectorDrawable på Android, SF Symbols på iOS), borttagning av oanvänd kod (R8/ProGuard), borttagning av oanvända resurser (lint → unused resources).

App Bundle (Android) — publiceringsformat där Google Play genererar en optimerad APK för varje enhet. App Bundle minskar nedladdningsstorleken med 20-40%. Dynamic Delivery — moduler som laddas ner på begäran (on-demand feature modules). Motsvarigheten på iOS är On-Demand Resources (ODR): resurser som laddas ner efter första starten (spelnivåer, videor).

Lat laddning — teknik där moduler och bibliotek inte laddas vid start, utan laddas vid behov. Split APK (Android) och App Slicing (iOS) — uppdelning av appen i arkitekturslots: arm64-v8a, x86_64. Optimering av appstorlek — en kontinuerlig process: analysera APK-sammansättningen (Analyze APK i Android Studio), ta bort dubblettikoner, använd SVG istället för flera PNG-densiteter. På IT Sectr inkluderar vi byggstorlekskontroll i CI/CD för varje MR.

Vanliga frågor

Vad är ANR och hur undviker man det?

ANR (Application Not Responding) — dialogruta på Android som visas om huvudtråden är blockerad i mer än 5 sekunder. För att undvika ANR, flytta alla tunga operationer (nätverk, databas, filbehandling) till bakgrundstrådar. Motsvarigheten på iOS är frozen UI, när appen slutar svara på beröring.

Vad är en minnesläcka och Retain Cycle?

En minnesläcka uppstår när ett objekt inte kan frigöras eftersom det fortfarande finns referenser till det. En Retain Cycle är en situation i iOS/Objective-C där två objekt refererar till varandra (A → B → A) och ARC inte kan frigöra något av dem. Lösning: weak/unowned-referenser och snabb rensning av callbacks.

Vilka verktyg ska man använda för profilering?

För iOS: Instruments (Time Profiler, Allocations, Leaks). För Android: Android Profiler (CPU, Memory, Network), LeakCanary (minnesläckor), StrictMode (trådöverträdelser). Det rekommenderas att kombinera profilering under utveckling och integration.

Hur skiljer sig Cold Start från Warm Start och Hot Start?

Cold Start — appen startas från början: processen skapas, klasser laddas, Application.onCreate körs. Warm Start — processen finns, men Activity/ViewController återskapas. Hot Start — Activity/ViewController finns redan i minnet, visas bara. Cold Start är långsammast (1-5 sekunder) och är avgörande för användarupplevelsen.

Hur minskar man storleken på en mobil app?

Huvudmetoder: ta bort oanvända resurser och kod (använd R8/ProGuard), vektorisera bilder (VectorDrawable, SF Symbols), komprimera PNG/WebP (Android), använd App Bundle istället för APK, ta bort onödiga bibliotek, använd lat laddning för moduler. Storleksoptimering kan minska APK:n med 40-60%.

Sammanfattning

  • ANR och krasch — de främsta stabilitetsproblemen; löses med bakgrundstrådar och kraschrapporter
  • Minnesläcka och Retain Cycle — främsta orsakerna till OOM; löses med svaga referenser och LeakCanary
  • GC (Stop-the-World-pauser) vs ARC (inga pauser men retain cycles) — olika minnesmodeller
  • Profilering — obligatorisk fas: Instruments (iOS), Android Profiler, LeakCanary, StrictMode
  • Cold Start — nyckeltal; optimera Application.onCreate och lat initialisering
  • App Bundle och WebP/VectorDrawable — främsta verktygen för att minska storleken med 20-60%
  • Prestanda är en kontinuerlig process, inte en engångsaktivitet; integrera mätvärden i CI/CD

Vi utvecklar en mobil applikation nyckelfärdigt

IT Sectr skapar iOS- och Android-applikationer för startups och företag sedan 2017. Vi ger dig råd och föreslår den bästa lösningen.

Diskutera projektet