Memóriát eszik és duzzad — mi ez, okok és hogyan kerülhető el

Szerző: IT Sectr Megjelenés: 2026-07-28 Olvasási idő: 10 perc

Memóriaszivárgás — az egyik legálomosabb probléma a mobil fejlesztésben. Az alkalmazás memóriája folyamatosan nő, amíg el nem éri az operációs rendszer által beállított határt, ami után OutOfMemoryError vagy kényszerített leállítás következik. A Square Engineering szerint körülbelül az Android-alkalmazások 40%-a rendelkezik legalább egy memóriaszivárgással, amely csak profilozással fedezhető fel. Nézzük meg a memórianövekedés okait és megelőzési módszereit.

Főbb pontok

  • GC reachability — az objektum nem törlődik, ha aktív hivatkozás van rá a gyökérkészletből
  • Statikus hivatkozások Activity-re vagy Context-re — a leggyakoribb szivárgási ok Androidban
  • LeakCanary — a szabványos eszköz automatikus szivárgásészleléshez Androidban
  • WeakReference — megoldás azokra a hivatkozásokra, amelyek nem akadályozhatják a szemétgyűjtést
  • Lifecycle-aware komponensek automatikusan törlik a feliratkozásokat a nézet megsemmisülésekor

Mi a memóriaszivárgás és az alkalmazás duzzadása?

Memóriaszivárgás (memory leak) — olyan helyzet, amikor egy objektum, amelyre az alkalmazásnak már nincs szüksége, továbbra is a heap-ben marad, mert aktív hivatkozás van rá a gyökérkészletből (GC Root). A szemétgyűjtő az ilyen objektumot élőnek tekinti és nem törli.

Memória duzzadása (memory bloat) — tágabb probléma, amikor az alkalmazás több memóriát fogyaszt, mint amennyi a jelenlegi feladatok elvégzéséhez szükséges. Okok: túlzott gyorsítótárazás, objektumok duplikálása, nem optimális adatszerkezetek és a heap fragmentálódása.

Androidban minden alkalmazás korlátozott heap-et kap (általában 64-512 MB-ot, az eszköztől és az OS verziójától függően). iOS-ben a korlátozás kevésbé szigorú, de a rendszer memóriafigyelmeztetést küld a határ megközelítésekor.

JellemzőAndroidiOS
Heap korlát64-512 MB (eszköztől függ)Implicit (rendszer)
SzemétgyűjtésART (Concurrent, Compact)ARC (Automatic Reference Counting)
Szivárgási mechanizmusGC Root hivatkozásokRetain ciklusok (erős hivatkozási ciklusok)
EredményOutOfMemoryErrorMemóriafigyelmeztetés → leállítás

A Facebook Engineering Blog szerint a memóriaszivárgások a mobil alkalmazásokban előforduló crash jelentések ~15%-ának okai. Androidban ehhez hozzáadódnak az ANR-ek a gyakori GC szünetek miatt memóriahiány esetén.

Tipikus memóriaszivárgási minták Androidban és iOS-ben

Statikus hivatkozás Activity-re — az Android szivárgások klasszikusa. Ha egy statikus mező vagy singleton hivatkozást tárol egy Activity-re, azt a GC még finish() után sem gyűjti be, amíg a singleton él. Az Activity egy nehéz objektum, amely View hierarchiát, erőforrásokat és Context-et tartalmaz.

kotlin
object LeakHolder {
    var activityRef: Activity ?= null // szivárgás: statikus hivatkozás Activity-re
}

class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle ?= null) {
        super.onCreate(savedInstanceState)
        LeakHolder.activityRef = this // ❌ A MainActivity-t soha nem gyűjti be a GC
    }
}

Anonim osztályok és lambdák — implicit módon hivatkozást tartanak a külső osztályra. Ha egy Runnable vagy Callback egy külső szolgáltatásnak kerül átadásra, és az Activity megsemmisül, az anonim osztály objektuma még mindig a sorban lóg, és nem engedi, hogy az Activity-t a szemétgyűjtő begyűjtse.

  • Handler késleltetéssel — ha az Activity megsemmisült, de a Handler.postDelayed még nem futott le, az Activity szivárog
  • Thread és AsyncTask — képernyőforgatáskor az Activity újra létrejön, de a régi Thread továbbra is tartja a hivatkozást a régi Activity-re
  • Retrofit/Callback — egy anonim Callback hivatkozást tart a presenter-re vagy fragment-re
  • Megfigyelők (Observers) — LiveData vagy RxJava feliratkozások törlés nélkül onDestroy-kor

iOS-ben a fő probléma a retain ciklus: két objektum erős hivatkozásokat tart egymásra, és az ARC egyiknek sem tudja nullázni a hivatkozás számlálóját. Tipikus eset: egy closure, amely erősen capture-öli a self-et, és a self, amely hivatkozást tart a closure-re.

Hogyan észleljük a memóriaszivárgásokat?

LeakCanary — a Square könyvtára automatikus szivárgásészleléshez Androidban. Az Activity vagy Fragment megsemmisülése után ellenőrzi, hogy az objektumot begyűjtötte-e a GC. Ha nem — heap dump-ot készít és megjeleníti a szivárgás nyomvonalát.

kotlin
// LeakCanary 2.x — auto-integráció Application-en keresztül
class ExampleApplication : Application() {
    override fun onCreate() {
        super.onCreate()
        // A LeakCanary automatikusan települ debug build-ben
        // ContentProvider-en keresztül — nulla kód beállítás
    }
}

// Kényszerített ellenőrzési hívás
AppWatcher.objectWatcher.watch(watchedObject, "leak description")

Android Studio Profiler — a beépített eszköz valós idejű memóriafigyeléshez. Lehetővé teszi heap dump rögzítését, gyanús objektumok (Retained Size > 1 MB) megtalálását és a GC root útvonal követését minden objektumhoz.

iOS-hez használja a Xcode Memory Graph Debugger-t. Ez vizualizálja az objektumok gráfját a memóriában, megjeleníti a retain ciklusokat, és lehetővé teszi a körkörös hivatkozások azonnali észlelését. Elérhető továbbá az Instruments > Allocations hosszú távú figyeléshez.

Szivárgásmegelőzési stratégiák

WeakReference — az alapvető mechanizmus azokhoz a hivatkozásokhoz, amelyek nem akadályozhatják a szemétgyűjtést. Ha a GC úgy dönt, hogy törli az objektumot, a WeakReference null-t ad vissza. Callback-ekhez, listener-ekhez és UI komponensekre mutató hivatkozásokhoz használják háttérszálakból.

Lifecycle-aware komponensek — az Android Jetpack-ben (Lifecycle, LiveData, Flow, coroutines) megvalósított architekturális megközelítés. A feliratkozások automatikusan törlődnek onDestroy-kor, ami kiküszöböli a szivárgások fő osztályát.

kotlin
class MyViewModel : ViewModel() {
    private val _data = MutableLiveData<List<User>>()
    val data: LiveData<List<User>> get() = _data

    fun loadData() {
        viewModelScope.launch {
            val result = repository.fetchData()
            _data.postValue(result)
            // a korutin automatikusan törlődik onCleared()-kor
        }
    }
}

viewModelScope és lifecycleScope — beépített CoroutineScope-ok Androidban, amelyek a megfelelő életciklus-eseménykor törlődnek. Ez kiküszöböli a korutinokon keresztüli szivárgásokat — a legáltalánosabb forgatókönyvet a modern Android fejlesztésben.

  • Ne használjon statikus hivatkozásokat Context, Activity, View vagy Fragment objektumokra
  • Törölje az összes RxJava feliratkozást a disposeBag / CompositeDisposable segítségével onDestroy-kor
  • Használjon [weak self] / [unowned self] iOS closure-ökben a retain ciklusok megelőzéséhez
  • Ellenőrizze a Bitmap-eket és nagy objektumokat — újra kell hasznosítani vagy nullázni kell őket

Memóriaprofilozó eszközök

Memory Profiler in Android Studio — a fő eszköz a heap figyeléséhez. Élő foglalásokat, heap pillanatképeket, objektumok számát típusonként jeleníti meg. Lehetővé teszi dump rögzítését és elemzését a MAT (Memory Analyzer Tool) segítségével a gyanús objektumok megtalálásához.

Eclipse MAT — asztali heap dump elemző. Az Android Studio-ból betöltött HPROF fájl után a MAT dominátor fát épít, megjeleníti az egyes objektumok retain méretét, és automatikus elemzést kínál a gyanús szivárgásokról a Leak Suspects Report segítségével.

Xcode Memory Graph — vizuális debugger retain ciklusokhoz. A Memory Graph Debugger gombra kattintva az Xcode leállítja az alkalmazást, felépíti az objektumok teljes gráfját a memóriában, és pirossal kiemeli a retain ciklusokat.

EszközPlatformJellemző
LeakCanaryAndroidAutomatikus szivárgásészlelés destroy után
Memory ProfilerAndroid StudioHeap dump + élő foglalások
Eclipse MATAndroidDominátor fa, Leak Suspects Report
Memory GraphiOS (Xcode)Retain ciklus vizualizátor

A Google I/O 2023 szerint azok az alkalmazások, amelyek debug build-ben használják a LeakCanary-t, 30-50%-kal csökkentik a memóriával kapcsolatos crash-ek számát a bevezetés utáni első 2 hónapban. Javasolt a LeakCanary hozzáadása a projekt onboarding fázisában.

Gyakran ismételt kérdések

Miben különbözik a memóriaszivárgás a duzzadástól?

Szivárgás — olyan objektumok, amelyek nem elérhetők a kód számára, de a GC nem törli őket az aktív hivatkozások miatt. Duzzadás — az alkalmazás olyan objektumokat tart a memóriában, amelyek logikailag szükségesek, de túlzott mennyiségben (pl. 50 MB gyorsítótár egy 80 MB-os futó alkalmazásban). A duzzadás építészetileg kezelhető, a szivárgás — a hivatkozások helyes kezelésével.

Hogyan találja meg a LeakCanary a szivárgásokat?

LeakCanary ObjectWatcher-t használ — az onDestroy() Activity után létrehoz egy WeakReference-t az Activity-re és elindítja a GC-t. Ha 5 másodperc után a WeakReference nem törlődik, a LeakCanary heap dump-ot készít, elemzi a legrövidebb hivatkozási láncot a GC Root-tól az objektumig, és megjeleníti a pontos szivárgási vermet a fájlnévvel és kódsorral.

Miért okoz a Bitmap gyakran OutOfMemoryError-t?

Bitmap a Java heap-en kívül, natív memóriában (native heap) foglal helyet. Egy Bitmap mérete = szélesség × magasság × 4 bájt (ARGB_8888). Egy 12 MP-es fénykép (4000×3000) 48 MB-ot foglal. Az Android nem mindig tudja időben felszabadítani a natív memóriát, ami több Bitmap felhalmozódásakor OOM-hez vezet még elegendő Java heap esetén is.

Mi az a retain ciklus iOS-ben?

Retain ciklus — olyan helyzet az ARC-ben, amikor két objektum erős hivatkozásokat tart egymásra, és a hivatkozás számláló soha nem ér nullát. Tipikus példa: ViewController erős hivatkozással egy closure-re, és a closure erősen capture-öli a self-et. Megoldás: használjon [weak self] vagy [unowned self] a closure-ökben.

Mekkora a maximális heap méret Androidban?

A heap mérete az eszköztől és az Android verziójától függ. Régi eszközökön (API 15-24) — 64-128 MB. Modern eszközökön (API 25+) — 256-512 MB. A pontos érték a ActivityManager.getMemoryClass() segítségével kapható meg. Nagy alkalmazásokhoz (játékok, szerkesztők) létezik largeHeap=true a manifest-ben, ami akár 1 GB-ot is biztosít.

Összefoglaló

  • Memóriaszivárgás — a GC által nem törölt objektum a gyökérkészletből származó aktív hivatkozás miatt; duzzadás — túlzott memóriafogyasztás nyilvánvaló szivárgás nélkül
  • Statikus hivatkozások Activity, Context, View objektumokra — az első számú szivárgási ok Androidban; megoldás — WeakReference vagy Application Context
  • Anonim osztályok és lambdák implicit módon hivatkozást tartanak a külső osztályra; nem törölt callback-ek — a második leggyakoribb ok
  • LeakCanary — az automatikus szivárgásészlelés szabványa Androidban; az integráció 5 percet vesz igénybe és 30-50%-kal csökkenti a crash arányt
  • lifecycleScope és viewModelScope automatikusan törlik a korutinokat destroy-kor, kiküszöbölve a szivárgások egész osztályát
  • Retain ciklusok iOS-ben weak/unowned self használatával oldhatók meg a closure-ökben és delegate-ekben
  • Profilozza a memóriát sprintenként legalább egyszer — a MAT vagy Memory Graph segítségével készített heap dump a code review részévé kell váljon

Kulcsrakész mobilalkalmazást fejlesztünk

Az IT Sectr 2017 óta készít iOS és Android alkalmazásokat induló vállalkozásoknak és vállalkozásoknak. Tanácsot adunk, és a legjobb megoldást javasoljuk.

Projekt megbeszélése

Olvassa el is