2012-06-13 3 views
5

Ho scritto del codice che carica un documento XML utilizzando un oggetto XmlDocument in modo da contare i suoi nodi. Ecco il metodo:C#: il metodo close di Xml.Load (file)

XmlDocument xml = new XmlDocument(); 
xml.Load(textBox1.Text); 
XmlNodeList nodes = xml.SelectNodes("//File"); 
foreach (XmlNode node in nodes) 
{ 
    number_of_childs++; 
} 

Il problema che sto affrontando è, durante l'importazione di un file di grandi dimensioni, ci vuole come 700MB di RAM. Se poi provo a fare qualche operazione sul file, o addirittura a leggere da esso per visualizzare i suoi dati in un ListView, l'applicazione prende come 2 GB di RAM. Quindi, mi stavo chiedendo, c'è un metodo che chiude lo XmlDocument e libera la sua memoria, rilasciando la RAM. È come se dimenticasse di rimuovere il suo contenuto dalla memoria.

risposta

12

No. La classe XmlDocument non implementa IDisposable, quindi non c'è modo di forzare il rilascio delle risorse a volontà. Se si ha realmente bisogno di liberare immediatamente la memoria utilizzata dal XmlDocument, l'unico modo per farlo sarebbe quello di fare quanto segue:

nodes = null; 
xml = null; 
GC.Collect(); 

Il garbage collector lavora su un thread separato, in modo che non possa ancora accadere immediatamente. Per forzare il garbage collection a verificarsi in modo sincrono, prima di continuare l'esecuzione del codice, è necessario chiamare WaitForPendingFinalizers, come ad esempio:

nodes = null; 
xml = null; 
GC.Collect(); 
GC.WaitForPendingFinalizers(); 

XmlDocument carica sempre l'intero documento in memoria in una sola volta. Se si desidera semplicemente eseguire un'iterazione dei nodi nel documento come flusso, caricando solo un bit alla volta, questo è ciò che la classe XmlReader utilizza. Tuttavia, si perde molta funzionalità in questo modo. Ad esempio, non c'è modo di selezionare i nodi tramite XPath, come si fa nel tuo esempio. Con XmlReader, devi scrivere la tua logica per determinare dove sei nel documento e se questo corrisponde a ciò che stai cercando.

+0

Grazie per questa informazione, ma non ha funzionato, ho applicato il tuo pezzo di codice ma riserva ancora la stessa quantità di memoria. –

+0

@ R.Vector vedi la mia modifica. –

+0

Sì, ha funzionato, ma il secondo passaggio dell'app è quello di leggere ogni nodo e digitarlo in un listview, quindi il problema esiste ancora, ma cosa succede se riesco a leggere ogni nodo di xml e liberarlo dalla memoria quando era memorizzato con successo da qualche parte <<< in questo modo sarebbe meglio per la gestione della memoria. –

2

Se non si deve manipolare l'XML, basta leggere l'XML utilizzando XMLReader, che è oneway e il più veloce, con meno operazioni di memoria intense.

1

Non è necessario impostare l'oggetto su null. Il GC dovrebbe essere in grado di indicare se il documento non viene più utilizzato da solo. Ciò avverrà automaticamente quando è necessaria la memoria, ma se vuoi cancellarlo immediatamente chiama GC.Collect(). Vedi this thread per ulteriori discussioni.

+1

Sono d'accordo sul fatto che in genere non è un grosso problema e il GC alla fine rilascerà la memoria da solo, ma se chiami il garbage collector manualmente, devi impostare la variabile su null prima di chiamare GC.Collect, altrimenti l'oggetto verrà comunque referenziato e non verrà raccolto. –

+0

@Steven Doggart, la tua affermazione è vera solo nelle build di Debug. Nelle build di Release, l'impostazione su null non è necessaria: il GC è abbastanza intelligente da vedere che non è più referenziato senza impostarlo su null. Vedi http://stackoverflow.com/questions/5545288/garbage-collection-of-orphaned-objects-tree-nodes-works-for-the-release-exe per esempio. –

+0

@MattSmith Questo è sorprendente e interessante. Ciò è dovuto al fatto che la build Release, per impostazione predefinita, include ulteriori ottimizzazioni che imposteranno automaticamente la variabile su 'null' non appena non viene più utilizzata, o qualcosa del genere? –