Automatikus memóriakezelés

Az automatikus memóriakezelés az egyik szolgáltatás, amelyet a Common Language Runtime biztosít a felügyelt végrehajtás során. A Common Language Runtime szemétgyűjtője kezeli az alkalmazások memóriafoglalását és felszabadítását. A fejlesztők számára ez azt jelenti, hogy felügyelt alkalmazások fejlesztésekor nem kell kódokat írnia a memóriakezelési feladatok elvégzéséhez. Az automatikus memóriakezelés kiküszöbölheti az olyan gyakori problémákat, mint az objektum felszabadítása és memóriavesztés, vagy a már felszabadított objektumok memóriájának elérése. Ez a szakasz azt ismerteti, hogy a szemétgyűjtő hogyan foglalja le és szabadít fel memóriát.

Memória kiosztása

Új folyamat inicializálásakor a futtatókörnyezet egy összefüggő címterületet foglal le a folyamat számára. Ezt a fenntartott címteret felügyelt halomnak nevezzük. A felügyelt halom egy mutatót tart fenn arra a címre, ahol a halom következő objektuma lesz lefoglalva. Ez a mutató kezdetben a felügyelt halom alapcímére van állítva. A rendszer minden referenciatípust lefoglal a felügyelt halomra. Amikor egy alkalmazás létrehozza az első referenciatípust, a rendszer memóriát foglal le a típushoz a felügyelt halom alapcímén. Amikor az alkalmazás létrehozza a következő objektumot, a szemétgyűjtő az első objektumot közvetlenül követő címtérben lefoglalja a memóriát. Mindaddig, amíg a címtér rendelkezésre áll, a szemétgyűjtő továbbra is így foglal le helyet az új objektumok számára.

A memória lefoglalása a felügyelt halomból gyorsabb, mint a nem felügyelt memóriafoglalás. Mivel a futtatókörnyezet úgy foglal le memóriát egy objektum számára, hogy hozzáad egy értéket egy mutatóhoz, majdnem olyan gyors, mint a memória lefoglalása a veremből. Emellett mivel az egymást követő új objektumok egyidejűleg vannak tárolva a felügyelt halomtárban, az alkalmazások nagyon gyorsan hozzáférhetnek az objektumokhoz.

Memória felszabadítása

A szemétgyűjtő optimalizáló motorja határozza meg a legjobb időt a gyűjtemény végrehajtására a végrehajtott foglalások alapján. Amikor a szemétgyűjtő gyűjtést végez, felszabadítja az alkalmazás által már nem használt objektumok memóriáját. Az alkalmazás gyökerének vizsgálatával meghatározza, hogy mely objektumokat nem használják többé. Minden alkalmazás rendelkezik gyökerekkel. Mindegyik gyökér a felügyelt halom egy objektumára hivatkozik, vagy null értékűre van állítva. Az alkalmazások gyökerei közé tartoznak a statikus mezők, a helyi változók és paraméterek a szál veremén, valamint a PROCESSZORregisztrációk. A szemétgyűjtő hozzáfér a just-in-time (JIT) fordító és a futtatókörnyezet által fenntartott aktív gyökerek listájához. A lista segítségével megvizsgálja az alkalmazás gyökerét, és a folyamat során létrehoz egy gráfot, amely tartalmazza a gyökerekből elérhető összes objektumot.

A gráfban nem szereplő objektumok nem érhetők el az alkalmazás gyökeréből. A szemétgyűjtő szemétnek tekinti az elérhetetlen objektumokat, és felszabadítja a számukra lefoglalt memóriát. A gyűjtés során a szemétgyűjtő megvizsgálja a felügyelt halomhelyet, és megkeresi az elérhetetlen objektumok által elfoglalt címtérblokkokat. Ahogy felderíti az egyes elérhetetlen objektumokat, egy memóriamásoló függvény használatával tömöríti az elérhető objektumokat a memóriában, felszabadítva a nem elérhető objektumokhoz lefoglalt címterek blokkjait. Az elérhető objektumok memóriájának tömörítése után a szemétgyűjtő végrehajtja a szükséges mutatókorrekciókat, hogy az alkalmazás gyökerei az új helyükön lévő objektumokra mutasson. A felügyelt halom mutatóját az utolsó elérhető objektum után is elhelyezi. Vegye figyelembe, hogy a memória csak akkor lesz tömörítve, ha egy gyűjtemény jelentős számú elérhetetlen objektumot észlel. Ha a felügyelt halom összes objektuma túlél egy gyűjteményt, akkor nincs szükség memóriatömörítésre.

A teljesítmény javítása érdekében a futtatókörnyezet külön halomba foglalja a nagy objektumok memóriáját. A szemétgyűjtő automatikusan felszabadítja a nagy objektumok memóriáját. A nagyméretű objektumok memóriabeli áthelyezésének elkerülése érdekében azonban ez a memória nincs tömörítve.

Generációk és teljesítmény

A szemétgyűjtő teljesítményének optimalizálása érdekében a felügyelt halom három generációra oszlik: 0, 1 és 2. A futtatókörnyezet szemétgyűjtési algoritmusa számos általánosításon alapul, amelyeket a számítógépes szoftveripar a szemétgyűjtési sémákkal való kísérletezéssel talált igaznak. Először is gyorsabb a memória tömörítése a felügyelt halom egy részének, mint a teljes felügyelt halom számára. Másodszor, az újabb objektumok élettartama rövidebb lesz, a régebbi objektumok pedig hosszabb élettartamúak lesznek. Végül az újabb objektumok általában egymással kapcsolódnak, és az alkalmazás nagyjából azonos időben fér hozzá.

A futtatókörnyezet szemétgyűjtője a 0. generációs új objektumokat tárolja. Az alkalmazás életének korai szakaszában létrehozott, gyűjteményeket túlélő objektumok előléptetése és tárolása az 1. és a 2. generációban történik. Az objektum-előléptetés folyamatát a jelen témakör későbbi részében ismertetjük. Mivel gyorsabb a felügyelt halom egy részének tömörítése, mint a teljes halom, ez a séma lehetővé teszi, hogy a szemétgyűjtő felszabadítsa a memóriát egy adott generációban ahelyett, hogy a teljes felügyelt halom memóriáját felszabadítja minden alkalommal, amikor gyűjteményt végez.

A valóságban a szemétgyűjtő akkor végez gyűjtést, ha a 0. generáció megtelt. Ha egy alkalmazás új objektumot próbál létrehozni, amikor a 0. generáció megtelt, a szemétgyűjtő észleli, hogy a 0. generációban nem marad címtér az objektum lefoglalásához. A szemétgyűjtő egy gyűjteményt hajt végre a 0. generációs címtér felszabadítására tett kísérlet során az objektum számára. A szemétgyűjtő a 0. generációs objektumok vizsgálatával kezdődik, nem pedig a felügyelt halom összes objektumának vizsgálatával. Ez a leghatékonyabb módszer, mivel az új objektumok általában rövid élettartammal rendelkeznek, és várhatóan a 0. generációs objektumok nagy részét már nem fogja használni az alkalmazás a gyűjtemény végrehajtásakor. Emellett a 0. generációs gyűjtemények gyakran elegendő memóriát igényelnek ahhoz, hogy az alkalmazás továbbra is új objektumokat hozzon létre.

Miután a szemétgyűjtő végrehajtotta a 0. generációs gyűjteményt, tömöríti az elérhető objektumok memóriáját a jelen témakör korábbi, A memória felszabadítása című szakaszában leírtak szerint. A szemétgyűjtő ezután előlépteti ezeket az objektumokat, és figyelembe veszi a felügyelt halom 1. generációjának ezt a részét. Mivel a gyűjteményeket túlélő objektumok általában hosszabb élettartamúak, érdemes magasabb generációra előléptetni őket. Ennek eredményeképpen a szemétgyűjtőnek nem kell újrakiadnia az 1. és a 2. generáció objektumait minden alkalommal, amikor a 0. generációs gyűjteményt hajtja végre.

Miután a szemétgyűjtő elvégezte a 0. generációs első gyűjteményét, és előléptette az elérhető objektumokat az 1. generációra, a felügyelt halom 0. generációjának fennmaradó részét veszi figyelembe. A 0. generációban továbbra is lefoglal memóriát az új objektumok számára, amíg a 0. generáció meg nem telik, és egy másik gyűjteményt kell végrehajtania. Ezen a ponton a szemétgyűjtő optimalizáló motorja határozza meg, hogy szükséges-e az idősebb generációk objektumainak vizsgálata. Ha például a 0. generációs gyűjtemény nem igényel elegendő memóriát ahhoz, hogy az alkalmazás sikeresen végrehajtsa az új objektum létrehozására tett kísérletét, a szemétgyűjtő végrehajthatja az 1. generációs, majd a 2. generációs gyűjteményt. Ha ez nem ad vissza elegendő memóriát, a szemétgyűjtő a 2., 1. és 0. generációt képes összegyűjteni. Az egyes gyűjtemények után a szemétgyűjtő tömöríti az elérhető objektumokat a 0. generációban, és előlépteti őket az 1. generációra. Az 1. generációs objektumok, amelyek túlélik a gyűjteményeket, a 2. generációra kerülnek elő. Mivel a szemétgyűjtő csak három generációt támogat, a 2. generáció azon objektumai, amelyek túlélnek egy gyűjteményt, a 2. generációban maradnak, amíg nem lesznek elérhetetlenek egy jövőbeli gyűjteményben.

Memória felszabadítása nem felügyelt erőforrásokhoz

Az alkalmazás által létrehozott objektumok többségénél a szemétgyűjtőre támaszkodva automatikusan végrehajthatja a szükséges memóriakezelési feladatokat. A nem felügyelt erőforrások azonban explicit törlést igényelnek. A nem felügyelt erőforrások leggyakoribb típusa egy olyan objektum, amely egy operációsrendszer-erőforrást, például egy fájlfogópontot, egy ablakfogópontot vagy egy hálózati kapcsolatot burkol. Bár a szemétgyűjtő képes nyomon követni egy felügyelt objektum élettartamát, amely egy nem felügyelt erőforrást foglal magában, nem rendelkezik konkrét ismeretekkel az erőforrás eltávolításáról. Ha olyan objektumot hoz létre, amely nem felügyelt erőforrást foglal magában, ajánlott megadni a szükséges kódot a nem felügyelt erőforrás nyilvános ártalmatlanítási metódusban való törléséhez. Az Elidegenítési módszer megadásával lehetővé teszi az objektum felhasználói számára, hogy explicit módon szabadítsák fel a memóriát, amikor befejezték az objektum használatát. Ha olyan objektumot használ, amely egy nem felügyelt erőforrást foglal magában, ismernie kell az elidegenítést, és szükség szerint meg kell hívnia. A nem felügyelt erőforrások eltávolításáról és az Ártalmatlanítás implementálásának tervezési mintájáról további információt a Szemétgyűjtés című témakörben talál.

Lásd még