Domanda

Quali risorse devono essere ripulite manualmente in C # e quali sono le conseguenze del non farlo?

Ad esempio, supponiamo che io abbia il seguente codice:

myBrush = new System.Drawing.SolidBrush(System.Drawing.Color.Black);
// Use Brush

Se non pulisco il pennello usando il metodo dispose, suppongo che il garbage collector libera la memoria utilizzata al termine del programma? È corretto?

Di quali altre risorse ho bisogno per pulire manualmente?

È stato utile?

Soluzione

Tecnicamente tutto ciò che eredita da IDisposable dovrebbe essere eliminato in modo proattivo. Puoi utilizzare l'istruzione "using" per semplificare le cose.

http://msdn.microsoft.com/en-us/library /yh598w02.aspx

A volte vedrai un uso incoerente di oggetti derivati ??IDisposable nel codice di esempio della documentazione e nel codice generato dagli strumenti (ad esempio Visual Studio).

La cosa bella di IDisposable è che ti dà la possibilità di proattivamente rilasciare la risorsa non gestita sottostante. A volte vuoi davvero farlo - pensa ad esempio alle connessioni di rete e alle risorse di file.

Altri suggerimenti

Se non smaltisci qualcosa, verrà ripulito quando il garbage collector nota che non ci sono più riferimenti ad esso nel tuo codice, che potrebbe essere dopo qualche tempo. Per qualcosa del genere, non importa, ma per un file aperto probabilmente lo è.

In generale, se qualcosa ha un metodo Dispose, dovresti chiamarlo quando hai finito con esso, o, se puoi, avvolgerlo in un'istruzione usando :

using (SolidBrush myBrush = new System.Drawing.SolidBrush(System.Drawing.Color.Black))
{
    // use myBrush
}
  • Gestisce le strutture di dati interne di Windows.
  • Collegamenti al database.
  • handle di file.
  • Connessioni di rete.
  • riferimenti COM / OLE.

L'elenco continua.

È importante chiamare Dispose o ancora meglio, utilizzare il modello using .

using (SolidBrush myBrush = new System.Drawing.SolidBrush(System.Drawing.Color.Black))
{
    // use myBrush
}

Se non si smaltisce qualcosa, verrà ripulito quando il garbage collector nota che non ci sono più riferimenti ad esso, che potrebbe essere dopo qualche tempo.

Nel caso di System.Drawing.Brush , Windows manterrà le strutture interne di Windows per il pennello caricato in memoria fino a quando tutti i programmi non rilasciano il loro handle.

Le conseguenze della mancata eliminazione dei tuoi IDisposable possono variare da un impatto trascurabile sulle prestazioni al crash dell'app.

L'oggetto Brush nel tuo esempio verrà ripulito dal GC quando ne hai voglia. Ma il tuo programma non avrà avuto il vantaggio di quel po 'di memoria aggiuntiva che avresti guadagnato pulendolo prima. Se stai usando molti oggetti Brush, questo potrebbe diventare significativo. Il GC è anche più efficiente nel ripulire gli oggetti se non sono in circolazione da molto tempo, perché è un garbage collector generazionale.

D'altra parte, le conseguenze della mancata disposizione degli oggetti di connessione al database potrebbero comportare l'esaurimento molto rapido delle connessioni al database in pool e il blocco dell'app.

Utilizza

using (new DisposableThing...
{
    ...
}

In alternativa, se è necessario conservare un riferimento a un IDisposable nell'oggetto per la sua durata, implementare IDisposable sull'oggetto e chiamare il metodo Dispose di IDisposable.

class MyClass : IDisposable
{
    private IDisposable disposableThing;

    public void DoStuffThatRequiresHavingAReferenceToDisposableThing() { ... }

    public void Dispose()
    {
        Dispose(true);
        GC.SuppressFinalize(this);
    }

    protected virtual void Dispose(bool disposing)
    //etc... (see IDisposable on msdn)

}

In generale, tutto ciò che implementa IDisposable dovrebbe farti mettere in pausa e cercare la risorsa che stai utilizzando.

GC si verifica solo quando c'è pressione della memoria, quindi non è possibile prevedere quando. Anche se uno scaricamento di AppDomain lo attiverà sicuramente.

Come altri hanno già detto, l'utilizzo è tuo amico. Ho scritto questa voce del blog su come implementare IDisposable in un modo abbastanza semplice che sia meno soggetto a errori prendendo in considerazione le parti più importanti.

Un trucco che uso quando non ricordo se un determinato oggetto è una risorsa usa e getta è digitare " .Dispose " (al massimo!) dopo la dichiarazione per convincere Intellisense a verificarmi:

MemoryStream ms = new MemoryStream().Dispose

Quindi elimina .Dispose e usa la direttiva using ():

using(MemoryStream ms = new MemoryStream())
{
  ...
}

Bene, finché usi la versione gestita delle risorse e non chiami le API di Windows da solo, dovresti essere OK. Ti preoccupi solo di dover eliminare / distruggere una risorsa quando quello che ottieni è un IntPtr, come " windows handle " (e molte altre cose) sono conosciute in .NET e non un oggetto.

A proposito, la risorsa (come qualsiasi altro oggetto .NET) verrà contrassegnata per la raccolta non appena si esce dal contesto corrente, quindi se si crea il pennello all'interno di un metodo, verrà contrassegnato quando lo si esce.

Se è gestito (ovvero parte del framework) non devi preoccuparti. Se implementa IDisposable, avvolgilo in un blocco utilizzando .

Se si desidera utilizzare risorse non gestite, è necessario leggere i finalizzatori e implementare IDisposable da soli.

Ci sono molti più dettagli in questa domanda

Innanzitutto al termine del programma, si può presumere che la memoria utilizzata dal processo verrà eliminata con il processo stesso.

Mentre si usa dispose o destructor in.net, si deve capire che il momento in cui la funzione dispose viene chiamata dal GC non è deterministico. Questo è il motivo per cui si consiglia di utilizzare esplicitamente l'utilizzo o la chiamata dell'eliminazione.

Quando si utilizzano risorse come file, è necessario liberare oggetti di memoria come semafori e risorse che vivono al di fuori del mondo gestito di .net.

SolidBrush, ad esempio, è necessario disporre poiché è un oggetto GDI e vive al di fuori del mondo .net.

Il garbage collector non si libera solo al termine del programma, altrimenti non sarebbe veramente utile (su qualsiasi SO decente / recente, quando il processo termina, tutta la sua memoria viene automaticamente ripulita automaticamente dal SO).

Uno dei grandi vantaggi di C # rispetto a C / C ++ è che non devi preoccuparti di liberare oggetti allocati (il più delle volte almeno); il gc lo fa quando il runtime decide (varie strategie quando / come farlo).

Molte risorse non sono gestite da gc: file, risorse relative a thread (blocchi), connessioni di rete, ecc ...

Un posto da fare attenzione sono gli oggetti che sembrano piccoli in GC ma non sono ... Nell'API di SharePoint, ad esempio, l'oggetto SPWeb ha un footprint ridotto per quanto riguarda il GC e quindi avrà una bassa priorità per la raccolta, ma ha davvero catturato un mucchio di memoria (nell'heap credo) di cui il GC non sia a conoscenza. Incontrerai alcuni divertenti problemi di memoria se, ad esempio, ne stai predicando un sacco, ricordati sempre di usare o smaltire!

Piuttosto che pensare a un oggetto come "trattenere". risorse che devono essere rilasciate, è meglio pensare in termini di un oggetto come aver alterato qualcosa (possibilmente al di fuori del computer!) che lo sopravviverà, in un certo senso potrebbe essere dannoso se non annullato o "ripulito", ma che solo l'oggetto può ripulire. Mentre questa alterazione prende comunemente la forma di un oggetto concreto in una piscina contrassegnata come "occupata", la sua forma precisa non ha importanza. Ciò che conta è che le modifiche devono essere annullate e l'oggetto contiene le informazioni necessarie per farlo.

Il Garbage Collector gestirà tutte le risorse gestite. Nel tuo esempio, il pennello verrà ripulito quando il garbage collector decide, cosa che succederà qualche tempo dopo che l'ultimo riferimento al pennello non è più valido.

Ci sono alcune cose che devono essere ripulite manualmente, ma si tratta di puntatori recuperati da fonti non gestite, come le chiamate DLL, ma nulla all'interno di .NET Framework necessita di questo trattamento.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top