Pamiec w .NET

Download Report

Transcript Pamiec w .NET

Programowanie
Aplikacji Lokalnych
w Środowisku .NET
Organizacja pamięci
Samodzielne zarządzanie pamięcią
Pamięć w .NET
Pamięć > 2GB

W systemach 32b (począwszy od Windows 2000
Advanced Server), Windows XP Pro można zredukować
przestrzeń jądra do 1GB (i uzyskać 3GB w trybie
użytkownika)





/3GB w boot.ini
linker - /LARGEADDRESWARE
Problemy z kompatybilnością przy niestand. wykorzystaniu przez
programistów górnego bitu wskaźnika do
Żeby zobaczyć więcej niż 3GB system musi pracować w
trybie PAE –> pot. problemy ze sterownikami
Windows 64B – 4TB
Operacje na pamięci (Win32)

dwa etapy pobierania bloku pamięci
VirtualAlloc
 rezerwacja
MEM_RESERVE
 przydzielenie MEM_COMMIT

dwa etapy zwalniania bloku pamięci
VirtualFree
 oddzielenie
MEM_DECOMMIT
 przydzielanie MEM_RELEASE

atrybuty dostępu do bloku pamięci
VirtualProtect

blokowanie zrzucania pamięci na dysk
VirtualLock / Unlock
Pamięć wirtualna – dostęp
VirtualAlloc najpierw sprawdza czy pamięć
już została zamapowana i ew. nie robi
tego ponownie.
 Próba dostępu do pamięci
zarezerwowanej, ale nie przydzielonej
generuje wyjątek (ktory można obsłużyć)

Stan pamięci
statystyka systemu:
 GlobalMemoryStatus : 32Bit -> przestrzeń 4GB
2GB aplikacja 2GB system
 3GB+1GB – system boot.ini: „/3GB” oraz
IMAGE_FILE_LARGE_ADDRESS_AWARE dla aplikacji
64Bit -> >4GB


.NET:
 System.Management.ManagementClass("Win32_OperatingSystem")
 System.Management.ManagementClass.GetInstances
 System.Management.ManagementObject.Properties
stan przestrzeni adresowej:
 VirtualQuery
 VirtualQueryEx (hProcess, ...)
Reprezentacja danych
Typy wartościowe:

typy proste, stuktury

alokowane na stosie

nie można po nich dziedziczyć
Typy referencyjne:

obiekty

alokowane na stercie zarządzalnej

unikatowa tożsamość

dodatkowe pola (sync block, Method Table Pointer )
Reprezentacja
Kolejność pól

LayoutKind.Auto — o kolejności ułożenia decyduje CLR.

LayoutKind.Sequential — kolejność ułożenia odpowiada
kolejności definicji pól obiektu w kodzie źródłowym.
LayoutKind.Explicit – kolejność jest określona przez
podanie konkretnych offset’ów.


Boxing/unboxing
Boxing/unboxing
Object Test(Object obj) {
struct PktValue {
public byte X; public byte Y;
}
return obj;
}
PktValue v = new PktValue();
Object o = Test(v);
v = (PktValue) o;
Kolekcje generyczne
Przeciązanie matod Equals, Implementacja
Equatable<T>,IComparable<T>
interface IChangeBoxedPoint {
void Change(Int32 x, Int32 y);
}
struct Point : IChangeBoxedPoint {
private Int32 m_x, m_y;
public Point(Int32 x, Int32 y) { m_x = x; m_y = y; }
public void Change(Int32 x, Int32 y) {
m_x = x; m_y = y;
}
public override String ToString() {
return String.Format("({0}, {1})", m_x.ToString(), m_y.ToString());
}
};
Point p = new Point(1, 1); // 1
Console.WriteLine(p); // 2
p.Change(2, 2); // 3
Console.WriteLine(p); // 4
Object o = p; // 5
Console.WriteLine(o); // 6
((Point) o).Change(3, 3); // 7
Console.WriteLine(o); // 8
((IChangeBoxedPoint) p).Change(4, 4); // 9
Console.WriteLine(p); // 10
((IChangeBoxedPoint) o).Change(5, 5); // 11
Console.WriteLine(o); //12
Point p = new Point(1, 1); // 1
Console.WriteLine(p); // 2 Konwersja
p.Change(2, 2); // 3
Console.WriteLine(p); // 4 Konwersja
Object o = p; // 5 Konwersja + pot. niespójność -> 2 kopie
Console.WriteLine(o); // 6 ?
((Point) o).Change(3, 3); // 7 Konwersja jaka jest zawartość o?
Console.WriteLine(o); // 8
((IChangeBoxedPoint) p).Change(4, 4); // 9 Konwersja + zaw. p?
Console.WriteLine(p); // 10 Konwersja
((IChangeBoxedPoint) o).Change(5, 5); // 11
Console.WriteLine(o); //12
Życie obiektu wg. GC







Rezerwacja - new (IL->newobj)
Inicjalizacja (konstruktor)
Użycie
Deterministyczne uwolnienie zasobów (Dispose)
Zaznaczanie nieużytków (Mark)
Ew. Uwolnienie zasobów (Finalizacja)
Zwolnienie pamieci (Sweep&Pack)
GC Mark&Sweep&Compact
GC - Poszukuje o oznacza obiekty, które mają
korzeń w
 zmiennych statycznych
 zmiennych lokalnych
 referencjach miedzy-generacyjnych
 obiektach w kolejce do finalizacji
Niezaznaczone obiekty usuwa i kompaktuje stertę
Sterta zarządzana
Przydział nie wymaga przeglądania list
wolnych bloków)
 Możliwa jest reorganizacja sterty

Obiekty i śmieci
W momencie braku
pamięci przeprowadzane
jest odśmiecanie
Zaznaczane są:
 statyczne obiekty
 Lokalne obiekty
 paramerty funkcji

Obiekty będące własnością ów już
już zaznaczonych
Kto trzyma obiekt?
class Program {
static void Main(string[] args) {
event Action<int> actionsToDo;
….
{
var myObject = new …;
actions += myObject.ActionToDo;
…
}
//????
}
}
Ile razy wykona się GC?
class Program {
static void Main(string[] args) {
Timer timer = new Timer(OnTimer, null, 0, 1000);
Console.ReadLine();
}
static void OnTimer(object state) {
GC.Collect(); // wymuszenie pracy GC
}
}
Ile razy wykona się GC?
class Program {
static void Main(string[] args) {
Timer timer = new Timer(OnTimer, null, 0, 1000);
Console.ReadLine();
}
static void OnTimer(object state) {
GC.Collect(); // wymuszenie pracy GC
}
}
 1 raz – optymalizacja: kompilator “zapamietuje miejsce
do którego jest używana zmienna lokalna”
Generacje

Założenia:
obiekty żyją dłużej,
 starsze obiekty są potencjalnie silniej związane
 starsze

Po zakończeniu oznaczania usuwane są martwe
obiekty z b. Pokolenia a żywe są przemieszczane
Generacje




Sprzątanie Gen 0 – 1ms?
Gen 0 – domyslnie 0.5-4MB
Przypięte obiekty są promowane
Wolania m. generacyjne (sprawdzane w momencie
przypisania)
Sterta dużych obiektów (>85KB dla .Net <=4.5.1)
 Od razu trafiają di generacji 2
 Nie podlega kompaktowaniu (od wersji 4.5.1 jest to
możliwe jest ale tylko na rządanie)
 Zarządzana poprzez listę wolnych miejsc
Zarządzanie automatem
void GC.Collect(Int32 Generation)
 void GC.Collect()

GC.Collect(GC.MaxGeneration);

Int32 GetGeneration(Object obj)

void WaitForPendingFinalizers();
Konfiguracja GC
Wokstation -> praca przy jednym procesorze
Niewspółbieżna – wszystkie wątki robocze są zawieszone
na cały czas sprzątania
Współbieżna – przed .Net 4.0 większa część fazy
oznaczania jest wykonywan współbieżnie (2 generacja)
Współbieżna – od .Net 4.0 2 wątki
I foreground blokująco odśmieca 0,1 generację oraz
upakowuje 2
II background jest nieblokujący I odznacza (ale nie
upakowuje) 2 generację
Konfiguracja GC
Serwer -> każdy procesor ma swoją stertę, alokacja I
sprzątanie odbywają sie równolegle.
Od 4.5
Praca w tle (2 wątki – analogicznie do workstation)
Zbalansowana alokacja dużych obiektów –
rownomiernie rozłożona na wszystkie sterty
GC.Collect(2, GCCollectionMode.Optimized)
GCCollectionMode: Default | Forced | Optimized.
Konfiguracja GC
Batch – aplikacje bez GUI/operacji serwerowych
<gcConcurrent> jest zablokowany lub
oba <gcConcurrent> i <gcServer> są włączone.
Interactive – GUI
<gcConcurrent> is włączony i <gcServer> is
zablokowany
LowLatency – aplikacje z wymaganym krótkim czasem
odpowiedzi, wrażliwe na spowolnienie spowodowane
przez GC (-> renderowanie grafiki ?)
SustainedLowLatency: (od .NET 4.5) zarówno dla trybu
stacji roboczej, jak i serwera. Pozwala odwlekać pełne
odzyskiwanie pamięci dla długotrwałych operacji.
GCSettings.LatencyMode =
GCLatencyMode.SustainedLowLatency
Large Object Heap



Duże obiekty >= 85000KB
Obiekty z LOH trafiają od razu do najstarszej generacji
Nie jest upakowywana (począwszy od .Net 4.5.1 może
być upakowywana na żądanie)
Upakuj przy najbliższym sprzątaniu najstarszej generacji
GCSettings.LargeObjectHeapCompactionMode =
GCLargeObjectHeapCompactionMode.CompactOnce;

Uwalnianie zasobów
Na życzenie: Dispose
Automatyczne: Finalizator
IDisposeable
// Font : IDisposeable;
Font font1 = new Font("Arial", 10.0f)
...
font1.Dispose(); // finally?
using (Font font1 = new Font("Arial", 10.0f))
{
}
Gdzie zwalniany jest obiekt?
Finalizator
Jest przeznaczony do zwalniania zasobów
 Finalizatora nie definiuje sie explicite
 Finalizator jest generowany automatycznie - > destruktor
public class BaseObj {
public BaseObj() {
}
public ~ BaseObj () {
// zwalnianie zasobów np. Close(db_connection);
Console.WriteLine("In Finalize.");
}
/* protected override void Finalize() {
// zwalnianie zasobów np. Close(db_connection);
Console.WriteLine("In Finalize.");
}*/

Finalizator
Obiekty zawierające finalizator





są wolniej alokowane, dużo wolniej zwalniane
domyślnie „żyją jedną generację dłużej”
dotyczy to również wszystkich obiektów, do których
odwołuja się takie obiekty itd.
nie jest znana kolejność wołań finalizatorów
nie ma gwarancji ze finalizator zostanie uruchomiony
MyObject : CriticalFinalizerObject
void WaitForPendingFinalizers()
w przypadku zabicia procesu nic nie pomoże

F. nie sa wołane domyslnie dla klas bazowych (por.
destruktor)
Kolejka do finalizacji
kolejka obiektów do
finalizacji – nie
mogą one zostać
usuniete bez
finalizacji
Kolejka do finalizacji
kolejka obiektów po
finalizacji ale przed
dealokacją
powód: w jednej z kolejek (istnieją obiekty posiadające
do nich wskaźnik)
Wskrzeszenie obiektu?
Powód: W czasie finalizacji powstaje nowa referencja do obiektu
 rzucany jest wyjątek (tragedia!!!)
 przypisujemy coś do wskaźnika globalnego, statycznego, atrybutu
„żyjącego obiektu”
Problem:
 obiekt może być już „sfinalizowany”
Rozwiązanie:
 flaga – „finalizacja ukończona” wykluczająca operacje
Sterowanie mechanizmem finalizacji – przydatne gdy chcemy
finallizować na życzenie
GC.ReRegisterForFinalize(this);
GC.SuppressFinalize(this);
Pattern Finalize/Dispose
public class MyClass : IDisposable {
private bool disposed = false;
~MyResource()
{
Dispose (false);
}
public void Dispose() // Do not make this method virtual.
{
Dispose (true);
}
public void Close() // Do not make this method virtual.
{
Dispose (true);
}
Zwolnienie na życzenie
private void Dispose(bool disposing)
{
// Check to see if Dispose has already been called.
if(!this.disposed)
{
if(disposing) {
AllComponent.Dispose();
GC.SuppressFinalize(this);
}
CloseHandle(handle);
handle = IntPtr.Zero;
disposed = true;
}
}
Słabe referencje
void Method() {
Object o = new Object(); // silna referencja
WeakReference wr = new WeakReference(o);
o = null; // usuwamy silną referencję
o = wr.Target;
if (o == null) {
// GC zwolnił obiekt
}
else
{
// obiekt ciągle istnieje
}
}
Czy jest możliwy wyciek pamięci
w .NET?
btn.Click += OnBtnClick
Monitorowanie GC
System.Diagnostics.PerformanceCounter
Critical Object Finalizers
Podczas tworzenia pierwszego obiektu danego typu,
metoda finalizująca jest kompilowana przez kompilator
JIT (minimalizujemy ryzyko wystąpienia błędu braku
pamięci potem – brak kompilacji przy pierwszym
wołaniu)
Finalizator jest wykonywany po wszyskich finalizatorach
obiektów zwykłych
CLR wywołuje metodę finalizacji nawet gdy AppDomain
jest niespodziewanie zamykana przez aplikację
hostującą (np. IIS).
Ale nie możliwe jest dziedziczenie po innym obiekcie
(brak wielodziedziczenia)