MR04 Garbage Collector - Microsoft Center

Gestione della memoria
e delle risorse in .NET
Marco Russo
MCSD MCAD MCSE+I MCSA MCDBA MCT
Mail: [email protected]
Italian blog: http://blogs.devleap.com/marco.blog
www.devleap.it




Gestione e infrastruttura di rete
Smart Client: la potenza del PC e la connettività Web
Gestione dell'infrastruttura dei sistemi di produttività aziendale
Sicurezza e interoperabilità
Guest Speaker
Bill Gates
Non perdere l'appuntamento dedicato
ai professionisti IT e agli sviluppatori
Iscriviti su
www.microsoft.com/italy/technicalconference/default.mspx
DevLeap: chi siamo
• www.DevLeap.it
• Un gruppo di 5 persone con tanta voglia di
•
•
•
•
•
Studiare a fondo le tecnologie
Capire il “behind the scenes”
Implementare soluzioni reali
Confrontarsi con le problematiche reali
Sperimentare nuove idee
• Facciamo Corsi, Conferenze, Training
• Scriviamo libri
• http://www.devleap.it/fullcontact
www.devleap.it
Chi siete ?
•
•
•
•
•
Chi usa già .NET?
Chi usa C#?
Chi usa VB.NET?
Chi usa C++/Managed C++?
Chi conosce Java?
www.devleap.it
Agenda
•
•
•
•
•
•
•
•
•
Perché il Garbage Collector
Algoritmo mark-and-compact
F-reachable queue
Pattern IDisposable
Resurrection
Weak Reference
Algoritmo generazionale
Thread e Garbage Collector
Garbage Collector vs. Heap Win32
www.devleap.it
Perché il Garbage Collector
• La gestione della memoria è fondamentale
nei linguaggi a oggetti
• I modelli tradizionali sono deterministici:
•
•
•
•
Distruzione manuale (C, C++, Win32)
Reference counting (COM, VB)
Minore uso di memoria
Maggiore consumo di CPU
• Modelli alternativi (euristici):
• Mark/sweep
• Copy collect
• Mark/compact
www.devleap.it
Algoritmi di Garbage Collection
• Mark/Sweep
• Segna tutti gli oggetti “raggiungibili”
• Gli oggetti non raggiungibili vengono distrutti
• Crea frammentazione memoria libera
• Copy Collect
• Copia tutti gli oggetti raggiungibili in una nuova
zona di memoria (contigua)
• Aggiorna tutti i riferimenti agli oggetti copiati
• Libera la zona di memoria esaminata
• Mark/Compact
• Soluzione ibrida, implementata da .NET
www.devleap.it
Algoritmo mark-and-compact
• Allocazione sequenziale di tutti gli oggetti
• Alte prestazioni
a a
a.b
a2 b
a2.b
A a = new A();
NextObjPtr
a.b = new B();
A a2 = new A();
a2.b = new B();
www.devleap.it
Algoritmo mark-and-compact
•
•
•
•
L’operazione di Garbage Collection raccoglie
gli oggetti non raggiungibili
Avviene automaticamente quando l’heap
cresce
Pilotata manualmente da GC.Collect()
Due fasi:
1. Mark
individua la memoria non raggiungibile
2. Compact
sposta tutti gli oggetti all’inizio dell’heap,
aggiornando tutti i riferimenti
www.devleap.it
GC fase 1: Mark
• Identifica gli oggetti referenziati,
raggiungibili da posti conosciuti (root set):
•
•
•
•
•
Proprietà AppDomain
Registri CPU
Slot TLS
Variabili locali sullo stack
Membri statici delle classi
• Iterazione ricorsiva degli oggetti referenziati
per “segnare” tutti gli oggetti raggiungibili
www.devleap.it
GC fase 2: Compact
• Tutti gli oggetti “raggiungibili” vengono
spostati all’inizio dell’heap
• Tutti i riferimenti vengono aggiornati
• Lo spazio libero non resta frammentato
www.devleap.it
GC fase 1: Mark
NextObjPtr
Root set
Oggetti “vivi”
Oggetti non raggiungibili
Spazio libero
www.devleap.it
GC fase 2: Compact
Spazio recuperato
NextObjPtr
Root set
Oggetti “vivi”
Spazio libero
www.devleap.it
Finalization queue
• Gli oggetti che possiedono un finalizer non
possono essere subito raccolti dal GC
• In C# il distruttore è sinonimo di Finalize
• Chiamata del finalizer dopo collection
• Alla creazione di un oggetto che possiede
Finalize, viene aggiunto un riferimento
all’oggetto nella Finalization queue
• Durante il GC, gli oggetti referenziati solo da
Finalization queue finiscono in
F-reachable queue
www.devleap.it
F-reachable queue
• F-reachable queue contiene riferimento a
oggetti con finalizer da richiamare
• Alimentata da Finalization queue
• I riferimenti contenuti da Finalization e
F-reachable queue diventano parte del root set
www.devleap.it
F-reachable queue
F-reachable queue
Oggetti “vivi”
In attesa di Finalize
Spazio libero
Root set
www.devleap.it
F-reachable queue
• F-reachable queue viene smaltita in un
thread dedicato che agisce in background
• GC.WaitForPendingFinalizer() per attendere
che F-reachable queue sia vuota
• Ordine di chiamata su Finalize() non segue
eventuali gerarchie padre-figlio
• Per queste esigenze usare Dispose()
• Evitare di implementare Finalize se non è
necessario (migliori prestazioni)
www.devleap.it
Pattern IDisposable
• In alcuni casi serve un comportamento di
finalizzazione deterministica:
• Riferimenti a oggetti non gestiti
• Utilizzo di risorse che devono essere rilasciate
appena termina il loro utilizzo
• Non si possono usare i finalizzatori, che non
sono richiamabili direttamente
• Implementare l’interfaccia IDisposable
www.devleap.it
Pattern IDisposable (1)
class DisposeDemo : BaseClass, IDisposable {
OtherRes
otherRes;
private
disposed = false;
private void freeState {
if (!disposed) { // Evita doppia esecuzione
// Chiude risorse allocate (es. handle non gestiti)
disposed = true;
}
}
public void Dispose() {
freeState();
otherRes.Dispose();// Dispose oggetti membro
base.Dispose();
// Dispose classe base (BaseClass)
GC.SuppressFinalize( this );
}
~DisposeDemo() {
freeState();
}
}
www.devleap.it
Pattern IDisposable (2 a)
class BaseResource : IDisposable {
OtherRes
otherRes;
private
disposed = false;
protected virtual void Dispose( bool disposing ) {
if (!this.disposed) {
if (disposing) {
otherRes.Dispose(); // Dispose oggetti membro
}
CloseHandle( ... );
// Chiude risorse non gestite
this.disposed = true;
}
}
public void Dispose() {
Dispose( true );
GC.SuppressFinalize( this );
}
~DisposeDemo() {
Dispose( false );
}
}
www.devleap.it
Pattern IDisposable (2 b)
class MyResource : BaseResource {
private
disposed = false;
// Implementa già IDisposable
protected override void Dispose( bool disposing ) {
if (!this.disposed) {
if (disposing) {
// Dispose altri oggetti gestiti
}
// Chiude risorse non gestite
this.disposed = true;
}
base.Dispose();
}
// La funzione Dispose() è già implementata nella classe base
// Il finalizzatore che chiama Dispose(bool) virtuale è già
// implementato nella classe base
}
www.devleap.it
Componenti .NET
• System.Object
• Non implementa nessuna interfaccia
• System.ComponentModel.Component
• Implementa IDisposable col pattern (2)
• Deriva da MarshalByRefObject
• System.Windows.Forms.Control
• Deriva da System.ComponentModel.Component
• Controlli “progettabili” graficamente
• Per controlli interattivi derivare UserControl
• System.Web.UI.Control
• Implementa IDisposable col pattern (1)
www.devleap.it
Resurrection
• Chiamare GC.SuppressFinalize() per
eliminare l’oggetto da F-reachable queue
• Finalize() non verrà più richiamata
• Un oggetto può ri-registrare il finalizzatore
chiamando GC.ReRegisterForFinalize()
• Tecnica chiamata “resurrection”
• In Finalize() si assegna this ad un oggetto
raggiungibile da root set
• GC.ReRegisterForFinalize() garantisce la
successiva ri-esecuzione di Finalize()
• Da non usare se non si è più che sicuri !!
www.devleap.it
Resurrection
public class BaseObj {
// ...
~BaseObj() {
Application.ObjHolder = this;
GC.ReRegisterForFinalize( this );
}
// ...
}
class Application {
static public Object ObjHandler;
// ...
}
www.devleap.it
Weak Reference
• Un Weak Reference è un riferimento “debole”
ad un oggetto
• Non viene considerato come riferimento da
parte del Garbage Collector
• Se l’oggetto viene raccolto dal GC, il Weak
Reference vale null
• Utile per meccanismi di cache
• Esistono due tipi di Weak Reference:
• Short Weak Reference
• Long Weak Reference
www.devleap.it
Weak Reference
• Short Weak Reference
• Valido fino a che l’oggetto non viene finalizzato
• Long Weak Reference
• Valido anche dopo la finalizzazione
• Utilizzabile per Resurrection - consente di
chiamare GC.ReRegisterForFinalize()
WeakReference( Object target );
WeakReference( Object target, Boolean trackResurrection );
www.devleap.it
Algoritmo generazionale
• Ottimizzazione dell’algoritmo di GC
• Statisticamente gli oggetti più giovani hanno una
vita più breve
• Il GC definisce l’età in base alla durata della
presenza sull’heap
• Generazione: insieme di elementi che
sopravvivono ad un GC
• Le generazioni più vecchie vengono
analizzate dal GC meno sovente
www.devleap.it
Algoritmo generazionale
• Ad ogni GC gli oggetti che sopravvivono
vengono promossi di una generazione
• L’implementazione attuale definisce 3
generazioni
G2
Oggetti
sopravvissuti a
due o più GC
G1
Oggetti
sopravvissuti
a un GC
G0
Oggetti mai
sottoposti a GC
www.devleap.it
Algoritmo generazionale
• GC.GetGeneration() restituisce la
generazione di un oggetto
• Frequenza GC su generazioni più vecchie fino
a 1/10 di quelle recenti
• Il GC non segue i riferimenti che puntano a
generazioni più vecchie
• GC.Collect( n ) consente di specificare quante
generazioni esaminare
• Gli oggetti con Finalize() vengono promossi
almeno una volta
www.devleap.it
Large Object Heap
• Heap separato per oggetti di grandi
dimensioni (>20k)
•
•
•
•
Il loro spostamento è costoso
Di solito non sono frequenti
Gli oggetti non vengono spostati
Simile a un tradizionale heap C/C++
www.devleap.it
Thread e Garbage Collector
• Versioni di GC diverse per mono e multiprocessore
• Ogni processo ha un thread separato per
chiamare i Finalize() degli oggetti
• Priorità più alta non real-time
• I metodi Finalize() vengono sempre chiamati da
questo thread
• L’operazione di GC arresta tutti i thread
gestiti (root set deve essere noto)
• Thread hijacking
• Safe points
• Fully interruptible code
www.devleap.it
Thread hijacking
• In presenza di un metodo breve, l’indirizzo di
ritorno viene deviato verso il GC, che ritorna
poi al percorso originale
int bar()
{
return 42;
}
int foo()
{
int ret = bar();
return ret;
}
GC
www.devleap.it
Safe Points
• In metodi lunghi il jitter inserisce delle
chiamate che sospendono il thread se deve
essere eseguito il GC
int bar()
{
...
...
...
...
...
...
...
...
}
Se GC in
attesa,
sospende il
thread fino
a che il GC
non viene
completato
GC Safe Point
www.devleap.it
GC
Fully interruptible code
• In loop stretti il thread viene sospeso ed il GC
esamina una tabella generata dal jitter con gli
oggetti attivi (root set) ad ogni linea
...
08
09
10
11
12
13
14
15
while (condition) {
Foo a = new Foo();
Bar b = new Bar();
Foo c = new Foo();
a.DoSomething();
condition = c.Good();
}
...
www.devleap.it
Linea
Oggetti
09
{}
10
{a}
11
{a,c}
12
{a,c}
13
{c}
14
{}
Concurrent Garbage Collector
• Configurabile a livello di host CLR
• Parametro flags di CorBindToRuntimeEx()
• ConcurrentGC
• Non rallenta interfaccia utente
• Prestazioni complessive più basse
• Costruzione del grafo di raggiungibilità in
background
• Non-concurrent GC
• Agisce nello stesso thread del codice utente
• Migliori prestazioni complessive
• Indicato per applicazioni server
• Default in file configurazione runtime:
<configuration> <runtime> <gcConcurrent enabled="false"/>
</runtime> </configuration>
www.devleap.it
Garbage Collector vs. Heap Win32
• Allocazione più veloce
• Penalizzazione se l’oggetto ha Finalize
• Anche l’allocazione è più lenta
• Importante chiamare GC.SuppressFinalize()
su Dispose()
• Heap C++ per build Debug estremamente più
lento (anche 1.000 volte)
• Paragone difficile
• Il finalizzatore può essere richiamato in
background, mentre il distruttore è sempre
sincrono nel thread chiamante
www.devleap.it
Considerazioni finali
• Non interagire direttamente con GC se non
c’è un buon motivo
• Tentare di risolvere un bug chiamando
GC.Collect() non è un buon motivo!
• Evitare finalizzatori se le prestazioni
sono importanti
• Va più veloce della gestione Heap tradizionale
• Weak reference e Resurrection solo se c’è un
ottimo motivo
• Evitare di creare più problemi di quanti
se ne risolvono
www.devleap.it
Riferimenti utili
• Demo di tutte le funzionalità di GC:
C:\Program Files\Microsoft.NET\FrameworkSDK\Samples\
technologies\GarbageCollection
• Articoli di Jeffrey Richter
su MSDN Magazine:
http://msdn.microsoft.com/library/default.asp?url=/library/enus/dnmag00/html/GCI.asp
http://msdn.microsoft.com/library/default.asp?url=/library/enus/dnmag00/html/GCI2.asp
www.devleap.it
Altre Informazioni
• Dove posso ottenere maggiori informazioni
• www.devleap.it
• www.microsoft.com/msdn/italy
• msdn.microsoft.com
• Developer resources
• Microsoft Visual Studio.NET
• Microsoft .NET Framework SDK
• Microsoft Developer Network
www.devleap.it
Gestione della memoria
e delle risorse in .NET
I vostri feedback sono
importanti
• Scriveteci
Grazie della partecipazione
– A presto
– [email protected]
www.devleap.it