8

I have written some code that loads an XML document using an XmlDocument object so as to count it's nodes. Here is the method:

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

The problem that I am facing is, when importing a large file, it takes like 700MB of RAM. If I then try to do some operation on the file, or even read from it to display its data in a ListView, the application takes like 2GB of RAM. So, I was wondering, is there a method that closes the XmlDocument and frees its memory, releasing the RAM. It is like it's forgetting to remove its content from memory.

Steven Doggart
  • 43,358
  • 8
  • 68
  • 105
R.Vector
  • 1,669
  • 9
  • 33
  • 41

3 Answers3

19

No. The XmlDocument class does not implement IDisposable, so there is no way to force it to release it's resources at will. If you really need to immediately free the memory used by XmlDocument, the only way to do that would be to do the following:

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

The garbage collector works on a separate thread, so it may still not happen immediately. To force the garbage collection to occur synchronously, before continuing execution of your code, you must also call WaitForPendingFinalizers, as such:

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

XmlDocument always loads the entire document into memory at once. If you simply want to iterate through the nodes in the document as a stream, only loading a bit at a time, that is what the XmlReader class is for. However, you lose a lot of functionality that way. For instance, there is no way to select nodes via XPath, as you where doing in your example. With XmlReader, you have to write your own logic to determine where in the document you are and whether that matches what you are looking for.

Steven Doggart
  • 43,358
  • 8
  • 68
  • 105
  • Thank you for that information , but it didn`t work , i have applied your piece of code but it still reserve the same amount of memory. – R.Vector Jun 13 '12 at 13:43
  • Yeah it worked , but the second step of app is to read every node and type it into a listview , so issue still exist , but what if i can read each node of the xml and free it`s space from memory when it was successfully stored somewhere <<< that way would be better for memory management. – R.Vector Jun 13 '12 at 13:52
  • My example does do exactly that. If frees the memory that was used to load the XML, but obviously the list view control would still use memory to store the data in its list items. By the way, are you having serious performance issues with the memory use, or are you just noticing the memory going up and it just bothers your sensibilities? If it's just your sensibilities, you need to get used to ignoring it. Since .NET uses garbage collection, your application's memory consumption will fluctuate all over the place seemingly randomly. That's normal and expected. You shouldn't worry about it – Steven Doggart Jun 13 '12 at 13:58
  • @R.Vector Oops. I forgot to set nodes to null in my example. – Steven Doggart Jun 13 '12 at 14:00
  • Thank you so much @Steve , it really helped improving the application performance regarding memory usage , before improvement the app was taking about 2GB or RAM and crashing , but after improvement it takes only 1.4GB – R.Vector Jun 13 '12 at 15:04
2

There is no need to set your object to null. The GC should be able to indicate if the Document isn't being used any further on it's own. This will happen automatically as memory is needed but if you want to clear it immediately call GC.Collect(). See this thread for further discussion.

Fr33dan
  • 4,227
  • 3
  • 35
  • 62
  • 1
    I agree that it is typically not a big concern and the GC will eventually release the memory on it's own, but if you are going to call the garbage collector manually, you have to set the variable to null before calling GC.Collect, otherwise the object will still be referenced and it will not be collected. – Steven Doggart Jun 13 '12 at 13:49
  • @Steven Doggart, your statement is only true in Debug builds. In Release builds, setting to null is not necessary--the GC is smart enough to see that it is no longer referenced without setting it to null. See http://stackoverflow.com/questions/5545288/garbage-collection-of-orphaned-objects-tree-nodes-works-for-the-release-exe for example. – Matt Smith Apr 04 '13 at 12:51
  • @MattSmith That's surprising and interesting. Is that because the Release build, by default, includes additional optimizations which would automatically set the variable to `null` as soon as it is no longer used, or something? – Steven Doggart Apr 04 '13 at 12:55
  • @StevenDoggart, I believe it is just that the variable is considered no longer referenced after its last usage. I wouldn't expect that Release build adds in code setting the variable to null. It's more that the debug build causes the reference to exist longer than it would naturally to allow for looking at that variable in a debugger. – Matt Smith Apr 04 '13 at 13:29
  • @MattSmith In that example that you linked to, Hans was saying that even though the variable goes out of scope, the reference will still exist on the stack when in Debug. I suspect that if the variable is still in scope, the reference will still exist, even in Release. – Steven Doggart Apr 04 '13 at 13:51
  • @StevenDoggart, I wrote a little a little sample app using a class with a Finalizer along with `GC.Collect` and `GC.WaitForPendingFinalizers` that showed the difference in behavior between Release and Debug. The sample app showed that even while the variable was *in scope* it got finalized without setting it to null. I can send you the sample if you're interested. – Matt Smith Apr 04 '13 at 14:23
  • 2
    @StevenDoggart, Here's the sample app that shows different ordering between Debug and Release: http://codepad.org/zmI3vBlQ. – Matt Smith Apr 04 '13 at 15:41
  • @MattSmith This is the extremely interesting I had no idea there was any difference, thank you for pointing this out. – Fr33dan Apr 04 '13 at 16:00
1

If you do not have to Manipulate the XML, just read the XML using XMLReader, that is oneway and the fastest, with less memory intense operation.

Furqan Hameedi
  • 4,372
  • 3
  • 27
  • 34