saxus (statz) | #9, Agyfasz (419) |
3224 | #1c2f | ^ | Idézet | Sat, 28 Apr 2012 01:50:07 +02 |
84.3.*.* | *.catv.pool.telekom.hu |
Na, amit akartam írni, csak elfelejtettem. Na ez az, amit nem csinál meg egy menedzselt nyelv. Eleve a threadoknak semmi köze a memória allokációnak. Amit stacken foglalsz az a stack felszabadításával eleve törlődik (annak kezelésében AFAIK eleve nincs is különbség pl. egy C-hez képest). Sőt, maga a szál nem tárol semmilyen referenciát (mégis hol tárolna? Max., ami stacken tárolt referencia, de a referenciák pont ezért többek egy sima pointertől.) Ami meg a heapon foglalódik, az meg eleve nem refcounter alapján megy (különben tényleg el lehetne leakelni, mint pl. a PHP-t, vagy egy refcounteres memory managert). Jó, gondolom van az is, mert az a leggyorsabb módja annak, hogy megállapítsuk, hogy van-e élő referencia az objektumra. De már írtam, hogy mind a Java, mind a C# képes detektálni az elérhetetlen referenciákat és fel fogja szabadítani. Nem azonnal, de amikor van szabad CPU idő vagy szükség van rá, fel fogja. (Azt viszont meg nem mondom, hogy milyen gráfbejárásos csodával állapítja meg ezeket). Ugyanis a memóriamenedzsment úgy működik, hogyha valami miatt egy objektum memóriaszemétnek minősül, akkor bekerül egy Finalization Queue-be, amelyet a GC a következő futásakor kihajít a francba. (Pontosabban itt még kerülhet egy Freachable queue-be, ha pl. van finalizer - (kb. destruktor helyi megfelelője)) Amivel viszont valóban el lehet leakelni, az az, ha valamilyen olyan resource-t használsz, amely kívül esik a menedzselt hatókörön és/vagy OS erőforrásokat foglal le. Pl. file descriptor, valamilyen resource, pl. Font (ugye a Windows fontkezelését használja a háttérben), vagy COM interop. Valamint ide tartozik az is, amit pl. unmanaged környezetben hozol létre (ha pl. C++/CLI-ben foglalsz le malloc-al vagy new -el* vagy a Marshaling-on keresztül matatsz valamit.) De pl. pont ezekre van .NET-ben az using() {} nyelvi elem, amely ezeknek megakadályozására szolgál. Amennyiben kilépsz az adott context-ből, meghívja a Dispose() metódust az adott objektumon. (.NET -ben az IDisposable pattern van arra, hogy az ilyen erőforrásokat, amelyeket muszáj kézzel felszabadítani, meg tudd tenni.) Vagy a try-catch -nak is azért van finally szakasza, mert az mindig lefut, akár volt exception, akár nem, pont azért, hogy a takarításokat valahol meg tudd oldani. (Na persze, a .NET -es GC-nek is vannak meredek trükkjei, pl. lehetséges megölhetetlen objektumot létrehozni azzal, hogy a finalizerben valami kívülről elérhető referenciát rakunk meg újraregisztráljuk a GC-nél finalizálásra az objektumot. Persze ez ilyen nagyon ocsmány dirty trükk, inkább nyelvi érdekesség, mintsem valós felhasználás. Egyébként se szokás a finalizert nagyon használni, egyrészt mert ki tudja mikor fut a GC, másrészt gyakorlatban nemigazán van rá szükség, harmadrészt a felszabadításokat jellemzően a Disposable pattern keretein belül szokás megoldani.) * C++/CLI -ben gcnew/gcdelete van a managed dolgokra, a new/delete maradt a natív C++ dolgokra |