Finalizace v různých jazycích

Finaliser

Finalizace v různých jazycích
« kdy: 18. 03. 2018, 14:50:11 »
Zdravím, existuje někde nějaké porovnání chování finalizérů v různých jazycích? Co jsem totiž tak různě pochytil, tak třeba v Javě není jejich vykonání zaručeno, v C# (nepřekvapivě) dtto, ObjC je taky občas neprovede (někde v Lionu, teď už tam je tracing GC dávno deprec), naopak Go je vykonává poctivě. Obecně platí, že na ně není spoleh - na rozdíl od RAII nebo referenčních GC, ale nikde jsem nenašel jasný přehled důvodů, proč se chovají nespolehlivě a je lepší je nepoužívat.
« Poslední změna: 18. 03. 2018, 19:03:42 od Petr Krčmář »


Franta <xkucf03/>

Re:Finalizace
« Odpověď #1 kdy: 18. 03. 2018, 16:39:04 »
V Javě můžeš dosáhnout aspoň stejného výsledku jako RAII v C++: Java a princip RAII (CADRe) známý z C++

Jester

Re:Finalizace
« Odpověď #2 kdy: 18. 03. 2018, 16:42:29 »
V Javě můžeš dosáhnout aspoň stejného výsledku jako RAII v C++: Java a princip RAII (CADRe) známý z C++
OT jak kráva.

Sten

Re:Finalizace v různých jazycích
« Odpověď #3 kdy: 18. 03. 2018, 20:11:07 »
To nezaručení je často špatně chápáno. Java (a obecně žádný jazyk s GC, ani ten používající GC s refcountingem, pokud dojde k cyklům, tak refcounting nefunguje) nezaručuje, kdy budou finalizéry vykonány, protože z pohledu programu se GC nespouští deterministicky a objekty k uvolnění nevybírá deterministicky; GC se spouští, když samo uzná za vhodné, a vybírá objekty, které uzná za vhodné, takže třeba když máte spoustu volné paměti, tak se nespouští vůbec, a když jí máte méně, ale pořád dost, tak uvolňuje jen velké objekty. Problém je také, že zdroje uvolňované finalizéry GC nevidí, takže může třeba vyhlásit nedostatek paměti, přestože finalizér jednoho malinkého nereferencovaného objektu by ji uvolnil. Finalizéry nebudou vykonány, jen pokud program skončí, než ten objekt uvolní GC; v moderních operačních systémech se finalizace (flush, zavření souborů, uvolnění zámků ap.) vykoná automaticky při ukončení programu, takže to nevadí. Ale nikdy nedojde k situaci, kdy GC uvolní objekt a nevyvolá přitom finalizér.

Nicméně ani Javě nejde vše jen přes GC, i tam se mohou finalizéry vyvolat synchronně, pokud JIT/AOT překladač detekuje, že objekt nemůže utéct z funkce, nepoužije (pomalé) GC, ale alokuje jej s lokální referencí a tu při ukončení funkce uvolní (včetně vyvolání finalizéru; typicky tohle dělá třeba Dalvik na Androidu). Ale je to interní věc VM a není nijak zaručena, to chování se může měnit třeba i s velikostí funkce a jak často je spuštěna.

Sten

Re:Finalizace v různých jazycích
« Odpověď #4 kdy: 18. 03. 2018, 20:32:43 »
Pak je tedy ještě problém s výjimkami ve finalizéru. Výjimky jsou zachyceny GC a do programu se nepropagují (ono to ani nejde, vylétávaly by na náhodných místech). To je problém třeba u I/O operací, kde až close/flush potvrzuje zapsání dat, takže váš program nemusí detekovat, že se data nezapsala.


Jester

Re:Finalizace v různých jazycích
« Odpověď #5 kdy: 19. 03. 2018, 01:05:59 »
pokud JIT/AOT překladač detekuje, že objekt nemůže utéct z funkce, nepoužije (pomalé) GC, ale alokuje jej s lokální referencí a tu při ukončení funkce uvolní (včetně vyvolání finalizéru
Finalizér je nekoncepční věc naroubovaná na objekty v Javě, protože někoho napadlo, že by mohly fungovat jako destruktory. Ono vůbec tracing GC přináší víc problémů, než řeší. Jinak v Go se při kolekci objekt s finalizérem neuvolní, jen se finalizuje a paměť se uvolní až při další kolekci.

Sten

Re:Finalizace v různých jazycích
« Odpověď #6 kdy: 19. 03. 2018, 07:38:02 »
Jinak v Go se při kolekci objekt s finalizérem neuvolní, jen se finalizuje a paměť se uvolní až při další kolekci.

Takhle to funguje i v Javě a AFAIK všech jazycích s GC. Ty lokální objekty jsou výjimka, protože nejsou sledované GC a pro jejich odstranění není potřeba vyvolat kolekci.