OutOfMemoryError i apputveckling: vad är det, orsaker och förebyggande metoder

Författare: IT Sectr Publicerad: 2026-03-29 Lästid: 9 min

OutOfMemoryError — ett dödligt undantag som uppstår när Java Virtual Machine (JVM) eller Android Runtime (ART) inte kan allokera minne för ett nytt objekt på grund av platsbrist i heapen. Enligt Square Engineering orsakas 70% av OutOfMemoryError i mobilappar av minnesläckor, inte av faktisk överskridning av gränsen. Att förstå orsakerna till OOM är nyckeln till stabil appfunktion.

Huvudpunkter

  • OutOfMemoryError — undantag vid otillräckligt Heap för att skapa ett nytt objekt
  • Heap (hög) — minnesområdet där alla Java/Kotlin-objekt lever
  • Bitmap — den största Heap-förbrukaren i Android, typisk OOM-källa
  • Heap Dump — en ögonblicksbild av heapen för att analysera vem som använder hur mycket minne
  • Behandling av OOM kräver åtgärdande av läckor och optimering av minnesförbrukning

Vad är OutOfMemoryError

OutOfMemoryError (OOM) — är ett undantag från VirtualMachineError-familjen i Java/Kotlin som signalerar att det inte går att allokera minne för ett nytt objekt. Till skillnad från checked-undantag är OOM ett Error och kräver inte hantering via catch — även om det tekniskt går att fånga. Efter att OOM inträffat är appen vanligtvis i ett instabilt tillstånd och det rekommenderas att stänga den.

Android har varje app en Heap-gräns som är inställd av enhetstillverkaren. För moderna smartphones med 6+ GB RAM är gränsen 256–512 MB, för budgetenheter — 128–192 MB. När den totala volymen av alla levande objekt överstiger denna gräns kastar ART en OutOfMemoryError.

Viktigt att förstå: OOM betyder inte alltid att enhetens fysiska minne är slut. Det betyder att appen har förbrukat sin Heap-gräns som satts av systemet. Andra appar kan ha ledigt minne, men din app kan inte använda det på grund av processisolering i Android.

Huvudorsaker till OutOfMemoryError

Fem scenarier leder regelbundet till OOM i mobilappar. Varje scenario är kopplat till en specifik datatyp eller operation.

Bitmap utan skalning

Bitmap — den största minnesförbrukaren i Android-appar. Att ladda en FullHD-bild (1920 × 1080) i originalstorlek tar 8.3 MB i ARGB_8888-format. Om det finns 50 sådana bilder i en RecyclerView — är det 415 MB, vilket överskrider Heap på vilken enhet som helst. Att ladda bilder utan inSampleSize — garanterad OOM på svaga enheter.

Använd Glide eller Coil för automatisk skalning. Dessa bibliotek laddar bilder i en storlek som passar View, inte originalupplösningen. För direkt användning av BitmapFactory.Options, använd inSampleSize: beräkna det som en tvåpotens så att den slutliga storleken inte överstiger 2048 × 2048 pixlar. Använd dessutom RGB_565 istället för ARGB_8888 för bilder utan transparens — detta halverar minnesförbrukningen.

kotlin
fun loadScaledBitmap(path: String, reqWidth: Int): Bitmap? {
    val opts = BitmapFactory.Options().apply {
        inJustDecodeBounds = true
    }
    BitmapFactory.decodeFile(path, opts)
    opts.inSampleSize = calculateSampleSize(opts.outWidth, reqWidth)
    opts.inJustDecodeBounds = false
    return BitmapFactory.decodeFile(path, opts)
}

Minnesläckor (ackumulering)

Ett läckage på några KB orsakar inte OOM. Men dussintals läckor på varje skärm ackumuleras: varje övergång till en skärm lägger till en läcka, GC kan inte frigöra objekt, Heap fylls. Typiskt mönster: användaren öppnar och stänger profilsidan 20 gånger → Heap växer med 200 MB → appen kraschar med OOM.

Installera LeakCanary i projektet för automatisk upptäckt av läckor. Det kommer att visa varje läckande objekt med exakt stack trace. Efter att alla läckor har åtgärdats blir Heap-förbrukningen stabil: efter att skärmen stängts återgår minnet till basnivån.

Stora filer i minnet

Att ladda filer helt i byte[] — den direkta vägen till OOM. En JSON-fil på 50 MB kommer vid parsning att skapa en sträng av samma storlek plus en DOM-modell. Videofiler som laddas i minnet, ljudbuffertar och stora protobuf-dataset — alla kan överskrida Heap-gränsen i en enda operation.

Bearbeta stora data med strömmar: InputStream med buffer på 4–8 KB, strömmande JSON-parser (Jackson eller Gson med JsonReader), MediaCodec för video. Anropa aldrig File.readBytes() på filer större än 10% av tillgängligt Heap.

Skapa många objekt i loop

Intensivt skapande av objekt i en loop utan mellanliggande GC kan leda till OOM, särskilt på enheter med litet Heap. Exempel: generering av 100 000 objekt i en for-loop som inte får plats i Heap innan GC hinner samla in dem. Detta förekommer oftare i spel och grafikredigerare.

Använd Object Pool för objekt som skapas och förstörs massvis. För numerisk data, använd primitiva typer (FloatArray istället för List<Float>). RecyclerView med ViewHolder Pool löser detta problem för UI-komponenter.

Fragmentering av Heap

Fragmentering — ett tillstånd där det totalt finns tillräckligt med ledigt minne, men det finns inget sammanhängande block för ett nytt objekt. ART kompakterar Heap under GC, men inte alltid framgångsrikt. Stora arrayer (Bitmap, byte[]) är mest känsliga för fragmentering.

ART på Android 8+ använder Generational GC, som minskar fragmentering genom att separera unga och gamla objekt. Undvik dock att allokera fragment av olika storlek i samma pool — försök använda förallokerade buffertar med fast storlek.

Heap-gränser i Android

Heap-gränsen i Android är inte konstant — den beror på tillverkaren, enhetsmodellen och OS-versionen. Google anger minimikrav via Compatibility Definition Document (CDD), men tillverkarna bestämmer de faktiska värdena.

EnhetskategoriTypiskt HeaplargeHeap
Budget (1–2 GB RAM)128–192 MB256–384 MB
Mellan (3–4 GB RAM)256–384 MB512 MB
Flaggskepp (6+ GB RAM)384–512 MB768 MB–1 GB
Surfplattor (4+ GB RAM)256–512 MB768 MB
Wear OS32–64 MBNej

Du kan begära en förhöjd gräns via android:largeHeap="true" i manifestet. Använd det försiktigt: att öka Heap löser inte läckageproblemet och kan försämra användarupplevelsen om systemet tvingas döda andra appar för att frigöra minne. För Wear OS är Heap-gränsen minimal — bara 32–64 MB, här är largeHeap inte tillgängligt och minnesbesparing är dubbelt kritisk.

Diagnostisera OutOfMemoryError

Diagnostisering av OOM kräver analys av Heap Dump och förståelse för vilka objekt som förbrukar minne. Android Studio tillhandahåller alla nödvändiga verktyg.

Steg 1: Fånga OOM-ögonblicket. I Android Memory Profiler, tryck på Record memory allocations och kör scenariot som orsakar kraschen. Profilern kommer att visa ett hopp i allokeringar före OOM. Om OOM inte reproduceras, minska Heap via android:smallHeap i en debug-build eller använd DDMS med manuellt GC-anrop.

Steg 2: Ta en Heap Dump vid tidpunkten för toppbelastning (före OOM). Öppna Dumpen i Android Studio: fliken Classes är sorterad efter Retained Size. De största objekten — Bitmap, byte[], String. För varje Bitmap, kontrollera storleken (width × height × 4 byte) och laddningsvägen via Stack Trace.

Steg 3: Analysera antalet återkommande objekt. Om du ser 200 identiska Fragment eller Activity — är det en läcka. Om 500 Bitmap av samma storlek — ett problem med bildcache. MAT (Memory Analyzer Tool) ger djupare analys med Dominator Tree som visar vilka objekt som håller 80% av Heap.

text
// Kommando för Heap Dump via adb
adb shell am dumpheap com.example.app /data/local/tmp/dump.hprof
adb pull /data/local/tmp/dump.hprof.

Strategier för att förebygga OOM

En omfattande strategi för att förebygga OOM omfattar fem skyddsnivåer: från arkitekturlösningar till övervakning i produktion.

Arkitekturlösningar

ViewModel + Repository-mönster separerar data från UI och förhindrar att View hålls kvar vid skärmrotation. ViewModel överlever Activity, dess data går inte förlorad och View kan återskapas utan dubblicering av data i minnet. Använd StateFlow istället för LiveData för explicit tillståndshantering.

Hantering av Bitmap och bilder

Glide — det obligatoriska biblioteket för att arbeta med bilder. Det skalar automatiskt, cachar (disk + minne) och återvinner Bitmap. Konfigurera diskCacheStrategy och skipMemoryCache för stora listor. För animerade bilder, använd Glide med GIF/WebP — de tar mindre minne än en sekvens av Bitmap.

Övervakning i produktion

Firebase Performance Monitoring spårar minnesförbrukning i realtid. Ställ in en varning när Heap är mer än 80% använt — det är en signal för kontroll. Crashlytics samlar OOM som ett undantag och visar det senast kända Heap-tillståndet före kraschen. För Android 11+, använd ApplicationExitInfo för detektering av OOM-avslut.

Testning på svaga enheter

Testa obligatoriskt appen på enheter med minimalt Heap (128–192 MB). En emulator med liten skärm och litet Heap emulerar en budgetenhet. Om appen fungerar på en sådan enhet kommer det inte att finnas några OOM-problem på flaggskepp. Använd Firebase Test Lab med riktiga enheter från olika priskategorier.

kotlin
// Kontrollera tillgängligt Heap före tung operation
fun canAllocate(requiredBytes: Long): Boolean {
    val runtime = Runtime.getRuntime()
    val free = runtime.freeMemory()
    return free > requiredBytes * 2 // reserv 50%
}

Vanliga frågor

Kan OutOfMemoryError fångas med try-catch?

Tekniskt ja, men det rekommenderas inte. Efter OOM är appen i ett instabilt tillstånd: nya allokeringar kanske inte fungerar och vissa objekt kan vara delvis skapade. Den enda rimliga åtgärden i catch — loggning och omstart av Activity.

Varför inträffar OOM inte på alla enheter?

Heap-gränsen är olika på olika enheter. En operation som kräver 300 MB kommer att krascha på en enhet med en gräns på 192 MB, men fungera på ett flaggskepp med 512 MB. Testa på enheter med minimala specifikationer för att upptäcka OOM-scenarier.

Hur påverkar largeHeap prestandan?

largeHeap ökar gränsen, men gör inte appen snabbare. GC-pauser blir längre eftersom det tar längre tid att samla en stor Heap. Systemet kan döda bakgrundsappar för att frigöra minne. Använd largeHeap endast för appar som objektivt behöver mycket minne (kameror, redigerare).

Vad är skillnaden mellan OOM och systemets dödande av en process?

OOM — undantag inuti appen vid brist på Heap. Systemets dödande (Low Memory Killer) — Linux-kärnans beslut att döda en process för att frigöra minne för andra appar. Vid systemets dödande får appen inget undantag — processen avslutas helt enkelt.

Hur mycket minne tar en Bitmap egentligen?

Formel: width × height × bytesPerPixel. ARGB_8888 = 4 B/pixel, RGB_565 = 2 B/pixel. FullHD Bitmap (1920 × 1080) i ARGB_8888 = 8.3 MB. 4K Bitmap (3840 × 2160) = 33 MB. Skala alltid bilder till den storlek som krävs för visning på skärmen.

Sammanfattning

  • OutOfMemoryError — dödligt undantag när appens Heap-gräns är förbrukad
  • Bitmap utan skalning — den främsta boven bakom OOM i mobilappar
  • Minnesläckor orsakar 70% av OOM genom ackumulering av objekt vid varje navigering
  • Heap-gräns varierar från 128 MB på budgetenheter till 512 MB på flaggskepp
  • Heap Dump med analys av Retained Size — det huvudsakliga verktyget för OOM-diagnostik
  • Glide eller Coil är obligatoriska för att arbeta med bilder av alla storlekar
  • Testning på enheter med minimalt Heap — must-have för alla projekt

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

Läs också