Správa paměti v prostředí .NET Martin Dybal Microsoft MSP http://sense4code.com/ Rozdělení dat v paměti •Instrukční paměť •Stack •By default 1MB •LIFO •Heap •Rozdělen na generace •Alokace pomocí new •Spravován Garbage Collectorem • • • • • Datové typy • •long •sbyte •short •struct •uint •ulong •ushort • Value types •bool •byte •char •decimal •double •enum •float •int Reference types •Array •class •interface •delegat •string Datové typy •Mýty •Hodnotové typy jsou na stacku a referenční na Haldě • Přiřazení hodnoty se liší u referenčních a hodnotových typů •Struktura •Hodnotový datový typ •Jsou menší, nemají takovou režii jako referenční typy •Demo • • • • • Heap •Code heap •Small object heap •Klasický heap •Large object heap •Objekty větší než 85KB •Process heap • • • Změna od .Net 4 a 4.5 Na servru Garbage collector(GC) •John McCarthny 1959 •Vyhledává již nepotřebné objekty •Process CLR • • • • John McCarthny 1959 První GarbageCollector napsal John McCarthny v Lispu v roce 1959 Je to proces Comon languge runtime. Je to správce paměti. Stará se o odklízení nepotřebných objektů z paměti Reference counting GC •Výhody •Dokáže objekty rychleji čistit •Nepozastavuje běh programu, vhodné pro RT systémy •Nevýhody •Vysoká režie •Alokace, přiřazení, dealokaci •Paměťová zátěž •Musí si pamatovat počet reference na každý objekt •Neumí řešit cyklickou referenci objektů • • Tracing GC •Výhody •Pokud nedochází ke collectingu, tak nijak neomezuje běh •Dokáže vyřešit cyklickou referenci objektů •Částečně řeší fragmentaci heapu •Nevýhody •Musí pozastavit běh programu •Odklízení je nedeterministické • • • • Garbage collecting • • A B E D C F H I J G E D C F H I J G A B A B C E F H D I J G Mark Sweep Označí vše jako garbage Identifikuje všechny kořeny Root – statické proměnné, glabání atd.. Průchod pomocí Reverse referencing Odstraní objekty z pamětí GC Roots •Lokální proměnné •GCHandles •Pin •Static •Registry •F-Reachable queue • • • • • Generace objektů •Generace 0 •Generace 1 •Generace 2 • • • Generace objektů • • • Generace 0 Generace 1 Generace 2 versionList version0 version1 version2 version3 Zanedbáme alokace mimo náš program Proměnou version, čísliuju podle i, aby jsme se v tom vyznali Proč se nám tam neoběvilo i? version3 version2 version1 version3 version2 version1 Generace objektů • • • Generace 0 Generace 1 Generace 2 versionList version0 Zanedbáme alokace mimo náš program Proměnou version, čísliuju podle i, aby jsme se v tom vyznali Proč se nám tam neoběvilo i? Generace objektů • • • Generace 0 Generace 1 Generace 2 versionList version0 version4 version5 version6 version7 version8 version5 version6 version7 Zanedbáme alokace mimo náš program Proměnou version, čísliuju podle i, aby jsme se v tom vyznali Proč se nám tam neoběvilo i? FINALIZATION QUE Spuštění garbage collecting Finalization •Finalize queue •F-reachable queue •ResourceWrapper, IDispoze • • • • • .NET Tips •String.Empty •Dispose Pattern •WeakReference •Large object heap compacting • Teď přejdem do praktické části Ukážeme si pár příkladů jak šetřit paměť Dispose Pattern •Není přesně dáno kdy se objekt odklidí •IDisposable •Destruktor •Using •CA2000 , CA1816 •GC.SuppressFinalize(this) • • • Pomocí Disposable můžeme řídit kdy objekt uvolní prostředky (například zámek k souboru) Popis dema Zapnutí analýzy kódu -> Project-> Properties -> Code Analysis -> Enable Code Analysis on Build CA2000 Dispose objects before losing scope In method 'Program.Main(string[])', call System.IDisposable.Dispose on object 'disposableClass' before all references to it are out of scope. IDisposableExample - Program.cs (Line 45) CA1816 Call GC.SuppressFinalize correctly Change 'DisposableClass.Dispose()' to call 'GC.SuppressFinalize(object)'. This will prevent unnecessary finalization of the object once it has been disposed and it has fallen out of scope. IDisposableExample - Program.cs (Line 12) String.Empty •Je efektivnější než "" • • Při použití “” se musí alokovat místo a zavolat konstruktor. String.Empty je reaodonly field ve třídě string. immutable WeakReference • • Pokud jsou na objekt jen měkké reference a dojde ke collectingu tak se smaže jakoby reference neexistovala. Existuje i Generická varianta, ale až od .NET 4.5 a má jiné rozhraní TryGet Memory profiling •Proč je object v paměti? •Co zabírá tolik paměti? •Memory leak • • • Nástroje od JetBrains jsou zdarma pro studenty. Memory Leak •Chyba správy paměti •Objekt uložený v paměti nepřístupný z programu • • • Klasický únik paměti není v .Netu možný. GC to nedovolí, navíc při ukončení aplikaci GC uvolní všechny zdroje. Problém ale může nastat za běhu kdy dostaneme OutOfMemory Memory Optimize Memory Traffic •Příliš mnoho alokací •Časté spouštění Garbage collectingu • • • Klasický únik paměti není v .Netu možný. GC to nedovolí, navíc při ukončení aplikaci GC uvolní všechny zdroje. Problém ale může nastat za běhu kdy dostaneme OutOfMemory Large object heap compacting •Od .Net 4.5.1 •Velmi časově náročné •GCSettings.LargeObjectHeapCompactionMode = GCLargeObjectHeapCompactionMode.CompactOnce; •GC.Collect(); Možnosti jsou pouze CompactOnce a Default, Default neprovádí compacting nikdy Verze GC v .NET • •Mobile •Workstation •Server • Pokud jsou na objekt jen měkké reference a dojde ke collectingu tak se smaže jakoby reference neexistovala. Existuje i Generická varianta, ale až od .NET 4.5 a má jiné rozhraní TryGet Bacground GC • •Workstation .NET 4.0 •Server .NET 4.5 •Lze vypnout • • • Pokud jsou na objekt jen měkké reference a dojde ke collectingu tak se smaže jakoby reference neexistovala. Existuje i Generická varianta, ale až od .NET 4.5 a má jiné rozhraní TryGet SustainedLowLatency • •GCSettings.LatencyMode = GCLatencyMode.SustainedLowLatency; • Pokud jsou na objekt jen měkké reference a dojde ke collectingu tak se smaže jakoby reference neexistovala. Existuje i Generická varianta, ale až od .NET 4.5 a má jiné rozhraní TryGet Large object support • •Možnost vytvářet objekty větší než 2GB •Pouze 64bitové aplikace • • Pokud jsou na objekt jen měkké reference a dojde ke collectingu tak se smaže jakoby reference neexistovala. Existuje i Generická varianta, ale až od .NET 4.5 a má jiné rozhraní TryGet