A szemétgyűjtést használó objektum-orientált programozási nyelvekben a véglegesítő egy speciális módszer, amelyet a futási környezet hív meg, mielőtt a szemétgyűjtő egy objektumot megsemmisít.
A véglegesítő egy olyan osztálymetódus , amelyet a futási környezet automatikusan hív meg az adott osztály objektumának a szemétgyűjtő általi használaton kívüliként való felismerése és az objektum eltávolítása (az általa elfoglalt memória felszabadítása) között . Egy adott objektum véglegesítése mindig lefut, miután a program már nem használja az objektumot, és mielőtt a szemétgyűjtő felszabadítaná az objektum memóriáját. Kényelmes úgy gondolni, hogy a véglegesítő közvetlenül az objektum memóriából való eltávolítása előtt hívódik meg, bár ez általában nem garantált.
A felületen a véglegesítő hasonlít egy osztályrombolóhoz , de a valóságban ezeknek a módszereknek a hatása és hatóköre egészen más. A különbség abból adódik, hogy a véglegesítő meghívásának pillanata a destruktorral ellentétben nincs mereven definiálva: a véglegesítőt mindig azelőtt hívják meg, hogy a szemétgyűjtő megsemmisítené az objektumot, de a megsemmisítés pillanata függ a megsemmisítés módjától. a szemétgyűjtő működését, a rendelkezésre álló RAM mennyiségét és a program memóriahasználati tevékenységét. Tehát, ha kevés a szabad memória, és folyamatosan új objektumok létrehozása történik, akkor gyakran van szükség a szemétgyűjtésre, és ennek megfelelően nagy valószínűséggel a véglegesítő hamarosan meghívásra kerül, miután az objektumot már nem használják. Ha sok a memória, és a program általi felhasználása kicsi, akkor az objektum használatának megszűnésétől a szemétgyűjtésig (és a véglegesítő hívásáig) sok idő telhet el. Sőt, ha sok a memória, és kevés vagy egyáltalán nem jön létre új objektum, akkor előfordulhat, hogy a szemétgyűjtő egyáltalán nem hívható meg, és a program végén az összes hozzárendelt memória visszakerül az operációs rendszerbe. rendszer; ebben az esetben előfordulhat, hogy a véglegesítő egyáltalán nem hívható meg.
Míg a destruktorokat nagyon gyakran használják az objektumok által elfoglalt szűkös rendszererőforrások (például egy fájlhoz vagy hardverhez való hozzáférés ) felszabadítására, a véglegesítőket a fent említett jellemzők miatt általában nem javasoljuk ilyen módon használni. Természetesen a véglegesítő bezárhatja a fájlt, vagy közölheti az operációs rendszerrel , hogy az eszköz már nincs használatban, azonban meghatározatlan idő telhet el attól a pillanattól kezdve, amikor az objektumot már nem használják, és a véglegesítő meghívásának pillanatáig. ez idő alatt az objektum által elfoglalt erőforrások nem kerülnek felhasználásra, hanem foglaltak maradnak. [egy]
A véglegesítők kiszámíthatatlanok, gyakran veszélyesek és gyakran szükségtelenek is.
– Joshua Bloch. Hatékony Java. Addison-Westley, 2001.A fentiek következtében a véglegesítők használata nagyon korlátozott. A szemétgyűjtő nyelvek a „megsemmisítés” tervezési mintát használják az erőforrások felosztására . A C# programozási nyelv az interfészen IDisposable és a kulcsszón keresztül implicit módon támogatja a "dispose" mintát, a usingJava 7 pedig egy hasonló "try-with-resources" mechanizmust vezetett be.
Az egyik ritka eset, amikor valóban szükség van véglegesítőre, az az, amikor egy osztály saját memóriakezelési mechanizmusait valósítja meg, amelyek harmadik féltől származó kódra támaszkodnak, amelyet nem a szemétgyűjtő rendszer kezel , például amikor egy Java osztály C-ben írt kódot használ az eléréshez. maximális hatékonyságot, vagy alacsony szintű műveleteket hajt végre. A külső kód működéséhez a memóriát szabványos C-mechanizmusokkal (malloc) kell lefoglalni, és saját segítségükkel fel kell szabadítani (ingyenes). Meghívhatja (és általában meg is kell) a memóriafoglalási függvényt az osztálykonstruktorban, és a külső memóriafelszabadító függvény hívásának megfelelő helye a véglegesítőben található, mivel ez a hely biztosítja, hogy a külső kód memóriája az objektum előtt kerül lefoglalásra. használatban van (amikor létrehozták), és csak akkor adják ki, ha a használat megszűnik. Ha a véglegesítőt nem hívják meg azonnal, vagy egyáltalán nem hívják meg, semmi rossz nem történik, mivel a lefoglalt külső memória a program lejárta után is automatikusan visszakerül a rendszerbe.
A véglegesítő használatának egy másik jó módja annak biztosítása, hogy az objektumokat a törlés előtt megtisztítsák. Ha egy objektum a létrehozás során vagy működése során a memórián kívül értékes rendszererőforrásokat rögzít (fájlokat vagy kommunikációs csatornákat nyit meg, I/O eszközökhöz csatlakozik), akkor nyilvánvalóan abban a pillanatban, amikor az objektumot a szemétgyűjtő törli, ezeket az erőforrásokat már fel kell szabadítani (akkor van egy objektum, amit törölni kell). A tisztítási hibák (amikor az objektumot bizonyos helyzetekben nem, vagy ami még rosszabb, nem tisztítják meg teljesen) nagyon alattomosak, nehezen észlelhetők, mivel a kód egy teljesen más részének végrehajtásakor jelennek meg, ahol a hiba történt. készült. Mint már említettük, nem bölcs dolog a véglegesítőben takarítani, mivel nem tudni, hogy mikor hívják, és hogy egyáltalán hívják-e. De a véglegesítőben meglehetősen helyénvaló és kényelmes ellenőrizni, hogy az objektum teljesen törölve van-e, és valamilyen formában hibaüzenetet ad ki, ha valamilyen erőforrás továbbra is rögzítve marad. Nem számít, hogy a véglegesítőt későn hívják, és nem minden alkalommal; amúgy ha objektumtisztítási hiba van, akkor előbb-utóbb a véglegesítő „elkapja”.
A véglegesítők különböző módon hozhatók létre. Egyes nyelveken a véglegesítő a szabványos könyvtár része. Általában ilyen esetekben a szabványos gyökérosztály virtuális metódusáról van szó, amelyből a rendszerben lévő összes többi osztály leszármazottja ( Java-ban ez az Object osztály finalize () metódusa). A véglegesítők speciális szintaxissal is deklarálhatók. A C# nyelvben a véglegesítő deklarálására szolgáló szintaxis a C++ destruktoroktól kölcsönzött - a Class osztály véglegesítője a ~Class() aláírású metódus lesz. A C#-on alapuló Nemerle nyelv elhagyta ezt a szintaxist, mert hibásnak tartották.