Garbage Collection (GC): mi ez, algoritmusok és szemétgyűjtés a mobilfejlesztésben

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

Az automatikus memóriakezelés szemétgyűjtéssel az Android platform kulcsmechanizmusa, amely az ART virtuális gépre épül. A Google Android Documentation, 2026 szerint a szemétgyűjtő felszabadítja a fejlesztőt a kézi memóriakezelés alól, automatikusan eltávolítva azokat az objektumokat, amelyekre már nincs hivatkozás. GC nélkül minden objektumfoglalás explicit free vagy delete hívást igényelne, ami a Java ökoszisztémában másodpercenként millió objektummal fizikailag lehetetlen.

Főbb pontok

  • Garbage Collection — automatikus memóriafelszabadító mechanizmus a nem használt objektumok eltávolításával Java és Android környezetben
  • Alapvető algoritmusok — Mark-and-Sweep, Copying Collection és Generational Collection határozzák meg a gyűjtés hatékonyságát
  • ART és Dalvik — az Android virtuális gép két megvalósítása, ahol az ART (Android Runtime) felváltotta a Dalvik-ot Android 5.0-tól
  • GC Pauses — az alkalmazás végrehajtásának megszakítása a gyűjtés során — a jank és teljesítményproblémák fő oka
  • GC optimalizálás — a foglalások csökkentése, objektumpoolok használata és a Collection típusok helyes megválasztása csökkenti a gyűjtő terhelését

Mi az a Garbage Collection (GC)?

Garbage Collection (GC) — egy automatikus folyamat a program által már nem használt objektumok által elfoglalt memória észlelésére és felszabadítására. A mobilfejlesztés kontextusában a GC az Android platformon az ART virtuális gépen, valamint a szabványos Java Virtual Machine-en keresztül kerül alkalmazásra.

Ellentétben a kézi memóriakezeléssel rendelkező nyelvekkel (C, C++), ahol a programozónak explicit módon kell meghívnia a free vagy delete utasítást, a GC teljesen átveszi az objektumok életciklusának nyomon követését. A fejlesztő új objektumokat hoz létre a new operátor segítségével, a gyűjtő pedig meghatározza azt a pillanatot, amikor egy objektum elérhetetlenné válik — vagyis nincs többá aktív hivatkozás rá.

A fő mérőszám a GC hatékonyságára — a szünetidő (pause time) és az átbocsátóképesség (throughput). A szünet az az időszak, amikor az alkalmazás végrehajtása felfüggesztődik a gyűjtés elvégzéséhez. Mobilos környezetben a 8–16 milliszekundumnál hosszabb szünetek kihagyott képkockákként (jank) érzékelhetők.

A Google I/O 2019 adatai szerint az ART Android 10-ben 2–4 ms-ra csökkentette a tipikus GC szüneteket, ami 70%-kal kevesebb az Android 4.4-es Dalvikhoz képest. Ennek ellenére a memória helytelen kezelése — gyakori objektumfoglalás ciklusokban, szükségtelen ideiglenes példányok létrehozása — továbbra is a teljesítményproblémák fő oka marad.

Hogyan működik a szemétgyűjtő: alapvető algoritmusok

Az összes GC megvalósítás Java-ban és Androidban néhány alapvető algoritmusra épül, amelyeket kombinálnak a szünetidő és a tisztítás teljessége közötti egyensúly elérése érdekében. Ezen algoritmusok megértése szükséges a GC-barát kód írásához.

Mark-and-Sweep

Mark-and-Sweep — a legegyszerűbb algoritmus, amely két fázisban működik. A Mark fázisban a gyűjtő bejárja az objektumgráfot, a gyökérhivatkozásoktól (root set) — lokális változók, statikus mezők, szálveremek — kezdve. Minden elérhető objektum megjelölésre kerül egy live jelzővel. A Sweep fázisban a gyűjtő áthalad a teljes kupacon és felszabadítja a meg nem jelölt objektumok memóriáját.

Hátránya — a memóriafragmentáció: Sweep után a szabad területek váltakoznak a foglaltakkal, ami megnehezíti a nagy objektumok foglalását. Mobilos forgatókönyvekben ez kritikus, mert a kupac általában kicsi (64–512 MB Androidon).

Copying Collection

Copying Collection két féltérre (semi-spaces) osztja a kupacot. Az aktív objektumok az egyik féltérből a másikba másolódnak tömören, megszakítás nélkül. A másolás után a régi féltér teljesen szabadnak nyilváníttatik. Az algoritmus teljesen megszünteti a fragmentációt, de kétszer annyi memóriát igényel.

Mobil környezetben a Copying Collection-t a generációs gyűjtők használják a fiatal objektumok gyors tisztítására, amelyek statisztikailag korán elhalnak (gyenge generáció hipotézis).

Generational Collection

Generational Collection generációkra osztja a kupacot: Young Generation (fiatal objektumok) és Old Generation (öreg objektumok, amelyek több gyűjtést is túléltek). A fiatal generáció gyűjtése (Minor GC) gyakran és gyorsan történik, mivel a legtöbb objektum fiatalon elhal. Az öreg generáció gyűjtése (Major GC vagy Full GC) ritkábban fordul elő, de tovább tart.

java
// Generációs GC bemutató: a fiatal objektumok gyorsan elhalnak
void processItems(List<Item> items) {
    List<Result> results = new ArrayList<>();       // éli az egész módszert
    for (Item item : items) {
        Result r = new Result(item.getValue());    // azonnal meghal
        if (r.isValid()) {
            process(r);                               // r szemétté válik
        }
    }
    saveResults(results);                             // results átkerül az Old Gen-be
}

Ebben a példában a Result objektumok a cikluson belül jönnek létre és azonnal szemétté válnak — ideális jelöltek a Young GC számára. A results objektum tovább él és átkerül az Old Generation-be. A generációk szétválasztása lehetővé teszi a Minor GC számára, hogy a fiatal objektumokat ezredmásodpercek alatt tisztítsa, anélkül hogy hozzányülna a régi kupachoz.

Garbage Collection Androidban: ART és Dalvik

Az Android a Dalvik VM-től az ART-ig (Android Runtime) vezető utat járta be, és a GC megvalósítása az egyik fő különbség köztük. A GC architektúra megértése Androidban segít olyan kód írásában, amely minimalizálja a szüneteket valódi eszközökön.

JellemzőDalvik (4.4-ig)ART (5.0+)
GC típusMark-and-Sweep Concurrent Mark-kalGenerációs + Concurrent
Tipikus szünet10–30 ms2–4 ms
KompatkálásNem (csak fragmentáció nő)Igen (háttérben, az alkalmazás megállítása nélkül)
AOT fordításJIT (Just-In-Time)AOT + JIT (hibrid)

Dalvik GC

Dalvik a Mark-and-Sweep és egy konkurens fázis kombinációját használta. A Concurrent Mark lehetővé tette az alkalmazás számára, hogy tovább dolgozzon az objektumgráf bejárása közben, de a Sweep fázis az összes szál leállítását igényelte (Stop-The-World). A kis RAM-mal rendelkező eszközökön (512 MB — 1 GB) a szünetek elérték a 30 ms-t, ami észrevehető lelassulást okozott a felületen. Ezenkívül a Dalvik nem kompaktálta a kupacot, így hosszú használat után a fragmentáció nőtt, és nagy objektumok (pl. Bitmap) foglalása OutOfMemoryError-t okozhatott, még elegendő összes szabad memória esetén is.

ART GC

ART (Android Runtime) bevezetett egy generációs gyűjtőt konkurens kompaktálással. A kupac három régióra oszlik: Young, Mature (az Old Generation megfelelője) és Large Object Space (12 KB-nál nagyobb objektumok számára). A Young régió gyűjtése párhuzamosan történik a szálak leállítása nélkül a legtöbb esetben. Android 10+-ban megjelent a Concurrent Copying — a kompaktálás háttérszálban történik Stop-The-World nélkül.

Az ART architektúrájának köszönhetően a tipikus GC szünetek 2–4 ms-ra csökkentek, és a fiatal objektumok túlsúlyával jellemzett forgatókönyvekben 0.5–1 ms-ra. Ez lehetővé tette az Android eszközök számára, hogy stabil 60 FPS-t biztosítsanak, még aktív memóriahasználat mellett is.

Szemétgyűjtők típusai Java-ban

A Java ökoszisztémában több GC megvalósítás létezik, mindegyik saját teljesítményprofillal. Az Android fejlesztéshez a választás az ART-ra korlátozódik, de a Java GC ismerete hasznos a mobilalkalmazások szerver részének írásakor és Kotlin Multiplatform fejlesztésnél.

Serial GC

Serial GC — egyszálú gyűjtő az alkalmazás teljes leállításával (Stop-The-World). Minden Mark, Sweep és Compact műveletet egy szál végez. A teljesítmény alacsony — nem használják mobil szerverekhez. Csak kis alkalmazásokhoz alkalmas, legfeljebb 100 MB kupaccal.

Parallel GC

Parallel GC (még Throughput Collector ként ismert) több szálat használ a gyűjtés minden fázisához. A maximális átbocsátóképességre (throughput) összpontosít — minimalizálja a GC-re fordított időt az alkalmazás futási idejéhez képest. A -XX:+UseParallelGC jelzővel aktiválható a JVM-ben.

G1 GC

G1 (Garbage-First) GC — az alapértelmezett gyűjtő Java 9+-ban. A kupac 1–32 MB-os régiókra van osztva. A G1 előrejelzi a szünetidőt és igyekszik a beállított határértéken (alapértelmezett 200 ms) belül maradni. Prioritás: először a legnagyobb szemétmennyiséggel rendelkező régiók kerülnek tisztításra (innen a név). A G1 hatékony nagy kupacú szerverekhez (4–64 GB) és előrejelezhető szünetekhez.

java
// G1 GC bekapcsolása 100 ms cél szünetidővel
// java -XX:+UseG1GC -XX:MaxGCPauseMillis=100 -jar app.jar

public class MemoryMonitor {
    private static final long THRESHOLD = 512 * 1024 * 1024; // 512 MB

    public void checkHeapUsage() {
        Runtime rt = Runtime.getRuntime();
        long used = rt.totalMemory() - rt.freeMemory();
        if (used > THRESHOLD) {
            System.out.println("A kupac használatának küszöbértéke túllépve: " + used);
            System.out.println("Fontolja meg a foglalások csökkentését");
        }
    }
}

A kupac megfigyelése Runtime-on keresztül lehetővé teszi a memóriaszivárgások korai észlelését. Ha a used túllépi a maximális kupac 80%-át stabil működés mellett — ez egy lehetséges szivárgás vagy túlezértékű memóriahasználat jelzője az alkalmazás részéről.

GC problémák és memóriaoptimalizálás mobilalkalmazásokban

Még a modern ART GC sem old meg minden problémát — a memória helytelen használata továbbra is a jank és ANR (Application Not Responding) fő oka. Nézzük át a fő forgatókönyveket és optimalizálási módszereket.

GC Pauses és Jank

GC Pauses — az alkalmazás szálainak leállítása a gyűjtés során. A képernyőn ez kihagyott képkockákként jelenik meg, amikor a két képkocka közötti idő meghaladja a 16.6 ms-t (60 FPS). Ha a GC 30 ms-ig tart, csak egy képkocka rajzolódik ki kettő helyett — a felhasználó a felület akadását tapasztalja.

A hosszú szünetek fő okai: nagyszámú élő objektum az Old Generation-ben, kupac fragmentáció, gyakori Full GC. Diagnosztikához az Android Studio Profiler és a systrace használható.

A GC terhelésének csökkentése

A fő szabály a GC-barát kódhoz — minimalizálni a foglalt objektumok számát. Minden új objektum nemcsak memóriafoglalást igényel, hanem későbbi gyűjtést is. Még ha a GC gyors is, 1000 felesleges foglalás másodpercenként 1000 ellenőrzést jelent a gyűjtő számára.

  • Kerülje az objektumok létrehozását ciklusokban — helyezze a létrehozást a cikluson kívülre, használja újra a lokális változókat
  • Használjon objektumpoolokat — Bitmap, byte[] és más nehéz struktúrákhoz használjon Object Pool-t vagy RecyclerView.ViewHolder-t
  • Előnyben részesítse a primitíveket — int Integer helyett, float Float helyett elkerüli az autoboxingot
  • Használjon SparseArray-t — HashMap<Integer, V> helyett az Android SDK-ban van SparseArray és LongSparseArray, amelyek primitívekkel dolgoznak
  • StringBuilder konkatenáció helyett — minden string összeadás új String objektumot hoz létre

Memóriaszivárgások

Memóriaszivárgás akkor keletkezik, amikor egy objektum elérhető marad, bár már nincs rá szükség. A GC nem tudja eltávolítani az ilyen objektumot, és a memória fokozatosan kimerül. Tipikus okok: le nem iratkozott figyelők, statikus hivatkozások Activity-re, anonym osztályok, amelyek külső kontextust fognak le, és le nem zárt Cursor/InputStream.

java
// Memóriaszivárgás: anonim osztály hivatkozást tart az Activity-re
public void startTask() {
    new Thread(new Runnable() {                    // implicit módon tartja a this-t (Activity)
        @Override
        public void run() {
            // hosszú művelet...
            System.out.println("Kész");
        }
    }).start();
}

// Javítás: statikus beágyazott osztály + WeakReference
private static class TaskRunnable implements Runnable {
    private WeakReference<Activity> activityRef;

    TaskRunnable(Activity activity) {
        this.activityRef = new WeakReference<>(activity);
    }

    @Override
    public void run() {
        Activity act = activityRef.get();
        if (act != null) {
            // biztonságos munka az Activity-vel
        }
    }
}

Ebben a példában az anonim Runnable implicit hivatkozást tart az Activity-re. Amíg a szál él — az Activity nem gyűjthető be a GC által, még akkor sem, ha a felhasználó már bezárta a képernyőt. A WeakReference + static class javítás megszakítja ezt a láncot, és lehetővé teszi az Activity újrahasznosítását.

Gyakran ismételt kérdések

Miben különbözik az Android GC a Java GC-től?

Az Android GC (ART) egy generációs gyűjtő konkurens kompaktálással, optimalizálva a korlátozott memóriájú mobileszközökhöz. A Java GC (G1, ZGC) szerver gyűjtők nagy kupacokkal és előrejelezhető szünetekkel. ART GC nem használ JVM jelzőket — minden beállítás automatikusan történik az operációs rendszer szintjén.

Mi az a Stop-The-World a GC-ben?

Stop-The-World — az a pillanat, amikor a gyűjtő leállítja az alkalmazás összes szálát, hogy biztonságosan bejárja az objektumgráfot vagy felszabadítsa a memóriát. Minél hosszabb az STW, annál észrevehetőbb a jank. Az ART a tipikus STW időt 2–4 ms-ra csökkentette a generációs architektúrának köszönhetően.

Hogyan észlelhető a memóriaszivárgás Androidban?

Használja az Android Studio Memory Profilert — megmutatja a kupac növekedését, a foglalások számát és lehetővé teszi a Heap Dump-ot. Mélyebb elemzéshez használja a LeakCanary-t — a könyvtár automatikusan észleli a szivárgásokat és megmutatja a GC gyűjtést akadályozó hivatkozási láncot.

Mikor történik Full GC és miért veszélyes?

Full GC — a kupac összes generációjának teljes gyűjtése, beleértve az Old Generation-t. Mobilalkalmazásokban a Full GC 50–200 ms-ig tarthat, észrevehető jank-ot vagy ANR-t okozva. Fő okok: kupac fragmentáció, memóriaszivárgások, az Old Generation küszöbértékének túllépése.

Hogyan segít a Kotlin elkerülni a memóriaszivárgásokat?

Kotlin strukturált konkurenciával rendelkező korutinokat kínál — a scope törlése automatikusan törli az összes gyermek korutint, megelőzve a szivárgásokat. Ezenkívül a Kotlinban van lazy delegált lusta inicializáláshoz és láthatósági tartomány operátorok, amelyek csökkentik az ideiglenes objektumok számát.

Összefoglalás

  • Garbage Collection — automatikus memóriakezelés az elérhetetlen objektumok eltávolításával, az Android Runtime alapja
  • Mark-and-Sweep — alapvető algoritmus kétfázisú gyűjtéssel, kupac fragmentációtól szenved
  • Copying Collection — megszünteti a fragmentációt az élő objektumok tömör féltérbe másolásával
  • Generational GC — generációkra osztja a kupacot (Young/Old), felgyorsítva a fiatal rövid élettartamú objektumok gyűjtését
  • ART Androidban — generációs gyűjtő konkurens kompaktálással és 2–4 ms szünetekkel, amely felváltotta a Dalvik-ot Android 5.0-ban
  • GC optimalizálás — foglalások csökkentése, objektumpoolok, primitívek wrapper-ek helyett és SparseArray HashMap helyett csökkentik a gyűjtő terhelését
  • Diagnosztika — Android Studio Profiler, systrace és LeakCanary a fő eszközök a memóriaproblémák azonosításához

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