Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Memory Leak using StreamReader and XmlSerializer

I've been googling for the past few hours and trying different things but can't seem to the bottom of this....

When I run this code, the memory usage continuously grows.

while (true) {     try     {         foreach (string sym in stringlist)         {             StreamReader r = new StreamReader(@"C:\Program Files\" + sym + ".xml");             XmlSerializer xml = new XmlSerializer(typeof(XMLObj), new XmlRootAttribute("rootNode"));             XMLObj obj = (XMLObj)xml.Deserialize(r);                                    obj.Dispose();             r.Dispose();             r.Close();         }     }         catch(Exception ex)      {         Console.WriteLine(ex.ToString());      }     Thread.Sleep(1000);     Console.Clear(); } 

XMLObj is a custom object

[Serializable()] public class XMLObj: IDisposable {     [XmlElement("block")]     public List<XMLnode> nodes{ get; set; }      public XMLObj() { }      public void Dispose()     {         nodes.ForEach(n => n.Dispose());         nodes= null;          GC.SuppressFinalize(this);     } } 

I've tried adding in GC.Collect(); but that doesn't seem to do anything.

like image 827
Alex999 Avatar asked May 27 '14 19:05

Alex999


People also ask

Is XmlSerializer thread safe?

Since XmlSerializer is one of the few thread safe classes in the framework you really only need a single instance of each serializer even in a multithreaded application. The only thing left for you to do, is to devise a way to always retrieve the same instance.

Why do we use XmlSerializer class?

XmlSerializer enables you to control how objects are encoded into XML. The XmlSerializer enables you to control how objects are encoded into XML, it has a number of constructors.


1 Answers

The leak is here:

new XmlSerializer(typeof(XMLObj), new XmlRootAttribute("rootNode")) 

XmlSerializer uses assembly generation, and assemblies cannot be collected. It does some automatic cache/reuse for the simplest constructor scenarios (new XmlSerializer(Type), etc), but not for this scenario. Consequently, you should cache it manually:

static readonly XmlSerializer mySerializer =     new XmlSerializer(typeof(XMLObj), new XmlRootAttribute("rootNode")) 

and use the cached serializer instance.

like image 93
Marc Gravell Avatar answered Oct 24 '22 15:10

Marc Gravell