OutOfMemoryError při vývoji aplikací: co to je, příčiny a metody prevence

Autor: IT Sectr Publikováno: 2026-03-29 Doba čtení: 9 min

OutOfMemoryError — fatální výjimka, která nastává, když Java Virtual Machine (JVM) nebo Android Runtime (ART) nemůže přidělit paměť pro nový objekt kvůli nedostatku místa v haldě (Heap). Podle Square Engineering je 70% OutOfMemoryError v mobilních aplikacích způsobeno úniky paměti, nikoli skutečným překročením limitu. Porozumění příčinám OOM je klíčem ke stabilnímu chodu aplikace.

Hlavní body

  • OutOfMemoryError — výjimka při nedostatku Heap pro vytvoření nového objektu
  • Heap (halda) — oblast paměti, kde žijí všechny objekty Java/Kotlin
  • Bitmap — hlavní spotřebitel Heap v Androidu, typický zdroj OOM
  • Heap Dump — snímek haldy pro analýzu, kdo a kolik paměti zabírá
  • Léčba OOM vyžaduje odstranění úniků a optimalizaci spotřeby paměti

Co je OutOfMemoryError

OutOfMemoryError (OOM) — je výjimka z rodiny VirtualMachineError v Java/Kotlin, která signalizuje nemožnost přidělit paměť pro nový objekt. Na rozdíl od checked výjimek je OOM Error a nevyžaduje zpracování přes catch — i když ho technicky lze zachytit. Po výskytu OOM je aplikace obvykle v nestabilním stavu a doporučuje se ji ukončit.

Na Androidu má každá aplikace limit Heap nastavený výrobcem zařízení. Pro moderní smartphony s 6+ GB RAM je limit 256–512 MB, pro rozpočtová zařízení — 128–192 MB. Když celkový objem všech živých objektů překročí tento limit, ART vyhodí OutOfMemoryError.

Důležité pochopit: OOM ne vždy znamená, že fyzická paměť zařízení došla. Znamená to, že aplikace vyčerpala svůj limit Heap nastavený systémem. Jiné aplikace mohou mít volnou paměť, ale vaše aplikace ji nemůže použít kvůli izolaci procesů v Androidu.

Hlavní příčiny OutOfMemoryError

Pět scénářů pravidelně vede k OOM v mobilních aplikacích. Každý scénář je spojen s určitým typem dat nebo operací.

Bitmap bez škálování

Bitmap — hlavní spotřebitel paměti v Android aplikacích. Načtení FullHD obrázku (1920 × 1080) v původní velikosti zabírá 8.3 MB ve formátu ARGB_8888. Pokud je v RecyclerView 50 takových obrázků — to je 415 MB, což překračuje Heap jakéhokoli zařízení. Načítání obrázků bez inSampleSize — zaručený OOM na slabých zařízeních.

Použijte Glide nebo Coil pro automatické škálování. Tyto knihovny načítají obrázky ve velikosti odpovídající View, ne původnímu rozlišení. Pro přímé použití BitmapFactory.Options aplikujte inSampleSize: vypočítejte ho jako mocninu dvou tak, aby konečná velikost nepřesáhla 2048 × 2048 pixelů. Dále použijte RGB_565 místo ARGB_8888 pro obrázky bez průhlednosti — to snižuje spotřebu paměti na polovinu.

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

Úniky paměti (nahromadění)

Jeden únik několika KB nezpůsobí OOM. Ale desítky úniků na každé obrazovce se hromadí: každý přechod na obrazovku přidává únik, GC nemůže uvolnit objekty, Heap se plní. Typický vzor: uživatel otevře a zavře obrazovku profilu 20krát → Heap vzroste o 200 MB → aplikace spadne s OOM.

Nainstalujte LeakCanary do projektu pro automatické odhalování úniků. Zobrazí každý uniklý objekt s přesným stack trace. Po opravě všech úniků se spotřeba Heap stabilizuje: po zavření obrazovky se paměť vrátí na základní úroveň.

Velké soubory v paměti

Načítání souborů celých do byte[] — přímá cesta k OOM. JSON soubor o 50 MB při parsování vytvoří řetězec stejné velikosti plus DOM model. Video soubory nahrané do paměti, audio buffery a velké protobuf datové sady — všechny mohou překročit limit Heap v jedné operaci.

Zpracovávejte velká data proudy: InputStream s bufferem 4–8 KB, streamovací JSON parser (Jackson nebo Gson s JsonReader), MediaCodec pro video. Nikdy nevolajte File.readBytes() na souborech větších než 10% dostupného Heapu.

Vytváření mnoha objektů v cyklu

Intenzivní vytváření objektů v cyklu bez mezilehlého GC může vést k OOM, zejména na zařízeních s malým Heapem. Příklad: generování 100 000 objektů v for cyklu, které se nevejdou do Heapu, než GC stihne je sesbírat. To je častější ve hrách a grafických editorech.

Použijte Object Pool pro objekty, které jsou hromadně vytvářeny a ničeny. Pro numerická data použijte primitivní typy (FloatArray místo List<Float>). RecyclerView s ViewHolder Pool řeší tento problém pro UI komponenty.

Fragmentace Heapu

Fragmentace — stav, kdy je volné paměti celkem dost, ale není souvislý blok pro nový objekt. ART kompaktuje Heap při GC, ale ne vždy úspěšně. Velká pole (Bitmap, byte[]) jsou nejcitlivější na fragmentaci.

ART na Android 8+ používá Generational GC, který snižuje fragmentaci oddělením mladých a starých objektů. Nicméně se vyhýbejte alokaci fragmentů různých velikostí ve stejném poolu — snažte se používat předem alokované buffery pevné velikosti.

Limity Heap v Androidu

Limit Heap v Androidu není konstanta — závisí na výrobci, modelu zařízení a verzi OS. Google stanovuje minimální požadavky prostřednictvím Compatibility Definition Document (CDD), ale výrobci nastavují skutečné hodnoty.

Kategorie zařízeníTypický HeaplargeHeap
Rozpočtová (1–2 GB RAM)128–192 MB256–384 MB
Střední (3–4 GB RAM)256–384 MB512 MB
Vlajková (6+ GB RAM)384–512 MB768 MB–1 GB
Tablety (4+ GB RAM)256–512 MB768 MB
Wear OS32–64 MBNe

Zvýšený limit lze požádat prostřednictvím android:largeHeap="true" v manifestu. Používejte ho opatrně: zvýšení Heap neřeší problém úniků a může zhoršit uživatelský zážitek, pokud je systém nucen zabíjet jiné aplikace pro uvolnění paměti. Pro Wear OS je limit Heap minimální — pouze 32–64 MB, zde largeHeap není k dispozici a úspora paměti je dvojnásob kritická.

Diagnostika OutOfMemoryError

Diagnostika OOM vyžaduje analýzu Heap Dump a pochopení, které objekty spotřebovávají paměť. Android Studio poskytuje všechny potřebné nástroje.

Krok 1: Zachyťte okamžik OOM. V Android Memory Profileru stiskněte Record memory allocations a spusťte scénář, který způsobuje pád. Profiler ukáže skok alokací před OOM. Pokud se OOM nereprodukuje, snižte Heap pomocí android:smallHeap v debug sestavení nebo použijte DDMS s ručním voláním GC.

Krok 2: Pořiďte Heap Dump v okamžiku špičkového zatížení (před OOM). Otevřete Dump v Android Studio: karta Classes je seřazena podle Retained Size. Největší objekty — Bitmap, byte[], String. U každého Bitmap zkontrolujte velikost (width × height × 4 byty) a cestu načítání přes Stack Trace.

Krok 3: Analyzujte počet opakujících se objektů. Pokud vidíte 200 stejných Fragment nebo Activity — to je únik. Pokud 500 Bitmap stejné velikosti — problém s cache obrázků. MAT (Memory Analyzer Tool) poskytuje hlubší analýzu s Dominator Tree, ukazující, které objekty drží 80% Heapu.

text
// Příkaz pro Heap Dump přes adb
adb shell am dumpheap com.example.app /data/local/tmp/dump.hprof
adb pull /data/local/tmp/dump.hprof.

Strategie prevence OOM

Komplexní strategie prevence OOM zahrnuje pět úrovní ochrany: od architektonických řešení po monitorování v produkci.

Architektonická řešení

ViewModel + Repository vzor odděluje data od UI a zabraňuje držení View při otáčení obrazovky. ViewModel přežije Activity, jeho data se neztratí a View může být znovu vytvořeno bez duplikování dat v paměti. Použijte StateFlow místo LiveData pro explicitní správu stavů.

Správa Bitmap a obrázků

Glide — povinná knihovna pro práci s obrázky. Automaticky škáluje, ukládá do cache (disk + paměť) a recykluje Bitmap. Nakonfigurujte diskCacheStrategy a skipMemoryCache pro velké seznamy. Pro animované obrázky použijte Glide s GIF/WebP — zabírají méně paměti než sekvence Bitmap.

Monitorování v produkci

Firebase Performance Monitoring sleduje spotřebu paměti v reálném čase. Nastavte alarm na obsazení Heap nad 80% limitu — to je signál pro kontrolu. Crashlytics shromažďuje OOM jako výjimku a ukazuje poslední známý stav Heap před pádem. Pro Android 11+ použijte ApplicationExitInfo pro detekci OOM ukončení.

Testování na slabých zařízeních

Povinně testujte aplikaci na zařízeních s minimálním Heap (128–192 MB). Emulátor s malou obrazovkou a malým Heap emuluje rozpočtové zařízení. Pokud aplikace funguje na takovém zařízení, na vlajkových lodích nebudou problémy s OOM. Použijte Firebase Test Lab s reálnými zařízeními různých cenových kategorií.

kotlin
// Kontrola dostupného Heapu před těžkou operací
fun canAllocate(requiredBytes: Long): Boolean {
    val runtime = Runtime.getRuntime()
    val free = runtime.freeMemory()
    return free > requiredBytes * 2 // rezerva 50%
}

Často kladené otázky

Lze zachytit OutOfMemoryError pomocí try-catch?

Technicky ano, ale nedoporučuje se. Po OOM je aplikace v nestabilním stavu: nové alokace nemusí fungovat a některé objekty mohou být částečně vytvořeny. Jediný rozumný krok v catch — logování a restart Activity.

Proč OOM nenastává na všech zařízeních?

Limit Heap je na různých zařízeních různý. Operace, která vyžaduje 300 MB, spadne na zařízení s limitem 192 MB, ale projde na vlajkové lodi s 512 MB. Testujte na zařízeních s minimálními specifikacemi pro odhalení OOM scénářů.

Jak largeHeap ovlivňuje výkon?

largeHeap zvyšuje limit, ale nezrychluje aplikaci. GC pauzy se prodlužují, protože sběr velkého Heapu trvá déle. Systém může zabíjet aplikace na pozadí pro zajištění paměti. Použijte largeHeap pouze pro aplikace, které objektivně potřebují hodně paměti (kamery, editory).

Čím se OOM liší od systémového zabití procesu?

OOM — výjimka uvnitř aplikace při nedostatku Heap. Systémové zabití (Low Memory Killer) — rozhodnutí Linuxového jádra zabít proces pro uvolnění paměti pro jiné aplikace. Při systémovém zabití aplikace nedostane výjimku — proces prostě skončí.

Kolik paměti skutečně zabírá Bitmap?

Vzorec: width × height × bytesPerPixel. ARGB_8888 = 4 B/pixel, RGB_565 = 2 B/pixel. FullHD Bitmap (1920 × 1080) v ARGB_8888 = 8.3 MB. 4K Bitmap (3840 × 2160) = 33 MB. Vždy škálujte obrázky na velikost potřebnou pro zobrazení na obrazovce.

Shrnutí

  • OutOfMemoryError — fatální výjimka při vyčerpání Heap limitu aplikace
  • Bitmap bez škálování — hlavní viník OOM v mobilních aplikacích
  • Úniky paměti způsobují 70% OOM hromaděním objektů při každé navigaci
  • Limit Heap se pohybuje od 128 MB na rozpočtových po 512 MB na vlajkových zařízeních
  • Heap Dump s analýzou Retained Size — hlavní nástroj diagnostiky OOM
  • Glide nebo Coil jsou povinné pro práci s obrázky jakékoli velikosti
  • Testování na zařízeních s minimálním Heap — must-have pro všechny projekty

Vyvineme mobilní aplikaci na klíč

IT Sectr vytváří aplikace pro iOS a Android pro startupy a podniky od roku 2017. Poradíme vám a navrhneme nejlepší řešení.

Prodiskutovat projekt

Přečtěte si také