Hulladékgyűjtés

A Programozás Wiki wikiből
(Hulladékgyűjtő szócikkből átirányítva)

A hulladékgyűjtés (angolul: garbage collection) az az eljárás, amelynek során az adott futtatókörnyezet vagy keretrendszer összegyűjti és megsemmisíti az immár használaton kívüli objektumokat és/vagy változókat, és felszabadítja az azok által lefoglalt memóriaterületeket és erőforrásokat. Nem minden programozási nyelv és környezet használ hulladékgyűjtést, de amelyik igen, abban ez a folyamat jellemzően megadott időközönként és/vagy az erőforrások szűkössé válásakor zajlik le.

A legismertebb hulladékgyűjtést alkalmazó rendszerek a Lisp, Java, egyes Basic változatok és a .NET keretrendszer.

A hulladékgyűjtés megvalósítására két, alapvetően különböző stratégiát szokás használni: a referenciakövetést és a referenciaszámlálást.

Referenciakövetés[szerkesztés]

A referenciakövetést alkalmazó hulladékgyűjtő feltérképezi az objektumok közötti hivatkozásokat, majd felszabadítja azokat az objektumokat, amelyeket a futó program már garantáltan nem tud elérni. Kezdeti lépésként vesz egy nyilvánvalóan elérhetőnek tekintett objektumhalmazt (általában a vermen található referenciákat és a globális változók tartalmát), majd a halmazt folyamatosan bővíti azon elemekkel, amelyek a halmazon kívül vannak, de van rájuk a halmazon belülről referencia. Az eljárás végén a halmaz tartalmazza az összes elérhető objektumot, így a halmazon kívüliek felszabadíthatók.

Az eljárás előnye, hogy szabályozható, mikor fusson le. Nagy mennyiségű objektum felszabadítása általában hatékonyabban végezhető, mint az egyenkénti felszabadítás, ezért van értelme időben elhúzni a gyűjtéseket. Más részről, ha túl ritkán történnek a gyűjtések, akkor sokáig is tartanak, ami a program megakadásához vezethet, valamint a felhalmozódó hulladék elveheti a memóriát más programok elől.

A legismertebb referenciakövető rendszerek a Lisp, a Java és a .NET keretrendszer.

Referenciaszámlálás[szerkesztés]

A referenciaszámlálás azt jelenti, hogy minden objektum kap egy számlálót, ami a rá hivatkozó referenciák számát tárolja. Ha módosítunk egy referenciát, először az eddig hivatkozott objektum számlálóját csökkentjük, majd az új objektum számlálóját növeljük. Azon objektumok, amelyek számlálója nulla, garantáltan elérhetetlenek, és felszabadíthatók. Ez a felszabadítás általában mohó módon történik, vagyis közvetlenül azután, hogy nullára csökkent a számláló.

Az eljárás előnye az egyszerű megvalósíthatósága. Bármilyen, manuális memóriakezelést támogató rendszerre ráépíthető extra rétegként. További előny, hogy az el nem érhető objektumok egyből felszabadulnak, vagyis a memóriahasználat jóval kisebb lehet, mint referenciakövetésnél. Ennek persze meg van az a hátránya is, hogy az egyenkénti felszabadítások összesen több erőforrást igényelnek, mint a követő módszer tömeges felszabadításai.

A módszer gyenge pontja, hogy nem képes a körkörös hivatkozások kezelésére: ha egy objektum közvetlenül vagy közvetetten referenciát tárol saját magára, akkor a referenciaszámlálója soha nem csökken 1 alá, és soha nem szabadul fel. Ha az így elszivárgó memória gondot okoz, lehetséges egy referenciakövetéses megoldás beépítése, mint másodlagos hulladékgyűjtő. Mivel az érintett objektumok száma csak töredéke az összes objektum számának, a másodlagos hulladékgyűjtésnek jóval ritkábban kell csak futnia, mint a tisztán követő megoldásoknál. Bizonyos speciális esetekben fel sem merül ez a probléma: pl. ha a hivatkozott objektumok nem tartalmazhatnak hivatkozást.

A megoldás népszerű azon szkriptnyelveknél, amiknek az interpretere C-ben íródott, pl. Perl, Python. Azon rendszereken is ezt szokás alkalmazni, ahol az erőforrások korlátozottak, és egy referenciakövetéses megoldás túl nagy terhet róna a rendszerre, pl. a régi Basic interpreterekben.

A referenciaszámlálást lehet alkalmazni a rendszer egyes részeihez is, míg a referenciakövetést csak globálisan szokás használni. Például a Delphi rendszerben a sztringek kezelése referenciaszámlálással történik, míg a rendszer maradéka manuális memóriakezelést követel. A másik tipikus példa az operációs rendszerek objektumkezelése: egy adott objektumra (pl. fájl, pipe, mutex) lehetséges több leírót (handle) nyitni a felhasználói programokból. Ezeket a leírókat egyesével kell lezárni, de az operációs rendszer csak az utolsó leíró lezárásakor szabadítja fel az objektumhoz tartozó erőforrásokat.