内存泄漏使用StreamReader和XmlSerializer

我一直在谷歌search过去的几个小时,尝试不同的东西,但似乎无法在这个底部….

当我运行这个代码时,内存使用量不断增长。

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是一个自定义对象

 [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); } } 

我试着添加GC.Collect(); 但是这似乎没有做任何事情。

泄漏在这里:

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

XmlSerializer使用程序集生成,并且不能收集程序集。 它为最简单的构造函数场景( new XmlSerializer(Type)等)进行了一些自动caching/重用,但不适用于这种情况。 因此,您应该手动caching它:

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

并使用caching的序列化器实例。

首先,即使抛出一个exception,你也应该丢弃你的StreamReader(对于XMLObj是一样的)。 使用using语句。 目前,当抛出exception时,你不会处理。

你有一个内存泄漏是不太可能的。 更可能的是,运行时并没有select收集内存。 即使GC.Collect也不一定会导致内存被释放。

处理非常大的XML文件(多GB)时,我遇到了类似的情况。 尽pipe运行时抓取大部分可用的内存,但是当内存压力允许时,它确实释放它。

您可以使用Visual Studio中的内存分析器来查看分配了哪些内存,以及它驻留在哪一代。

UPDATE

来自@KaiEichinger的评论是值得调查的。 它表明XmlSerializer可能正在为每个循环迭代创build一个新的caching对象定义

XMLSerializer构造函数使用reflection为要序列化的types创build临时程序集,并且由于代码生成非常昂贵,因此程序集基于每个typescaching在内存中。 但是很多时候,根名称将被改变,并且可以是dynamic的,并且不会cachingdynamic程序集。 所以每当上面的代码被调用时,它就会每次加载新的程序集,并保留在内存中,直到AppDomain被卸载。

从MSDN: 在这里input链接描述

为了提高性能,XML序列化基础结构dynamic生成程序集来序列化和反序列化指定的types。 基础设施find并重新使用这些程序集。 仅当使用以下构造函数时,会发生此行为:

XmlSerializer.XmlSerializer(types)

XmlSerializer.XmlSerializer(Type,String)

如果使用其他构造函数,则会生成相同程序集的多个版本,并且从不卸载,这会导致内存泄漏和性能下降。 最简单的解决scheme是使用前面提到的两个构造函数之一。 否则,您必须将程序集caching在Hashtable中,如以下示例所示。

=>所以要解决它,你必须使用这个构造函数XmlSerializer xml = new XmlSerializer(typeof(XMLObj))而不是XmlSerializer xml = new XmlSerializer(typeof(XMLObj), new XmlRootAttribute("rootNode"));

并将根XML属性添加到XMLObj类中。

 [Serializable()] [XmlRoot("root")] 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); } } 

我认为将XMLSerializer构造函数移到循环之外并caching其结果将解决此问题

我使用一个“caching”类,以避免每次需要序列化的东西时xmlserializer(也添加一个XmlCommentAttribute添加注释到序列化的属性在xml输出),对我来说,它的作品像沙姆希望帮助这个人:

  public static class XmlSerializerCache { private static object Locker = new object(); private static Dictionary<string, XmlSerializer> SerializerCacheForUtils = new Dictionary<string, XmlSerializer>(); public static XmlSerializer GetSerializer<T>() { return GetSerializer<T>(null); } public static XmlSerializer GetSerializer<T>(Type[] ExtraTypes) { return GetSerializer(typeof(T), ExtraTypes); } public static XmlSerializer GetSerializer(Type MainTypeForSerialization) { return GetSerializer(MainTypeForSerialization, null); } public static XmlSerializer GetSerializer(Type MainTypeForSerialization, Type[] ExtraTypes) { string Signature = MainTypeForSerialization.FullName; if (ExtraTypes != null) { foreach (Type Tp in ExtraTypes) Signature += "-" + Tp.FullName; } XmlSerializer XmlEventSerializer; if (SerializerCacheForUtils.ContainsKey(Signature)) XmlEventSerializer = SerializerCacheForUtils[Signature]; else { if (ExtraTypes == null) XmlEventSerializer = new XmlSerializer(MainTypeForSerialization); else XmlEventSerializer = new XmlSerializer(MainTypeForSerialization, ExtraTypes); SerializerCacheForUtils.Add(Signature, XmlEventSerializer); } return XmlEventSerializer; } public static T Deserialize<T>(XDocument XmlData) { return Deserialize<T>(XmlData, null); } public static T Deserialize<T>(XDocument XmlData, Type[] ExtraTypes) { lock (Locker) { T Result = default(T); try { XmlReader XmlReader = XmlData.Root.CreateReader(); XmlSerializer Ser = GetSerializer<T>(ExtraTypes); Result = (T)Ser.Deserialize(XmlReader); XmlReader.Dispose(); return Result; } catch (Exception Ex) { throw new Exception("Could not deserialize to " + typeof(T).Name, Ex); } } } public static T Deserialize<T>(string XmlData) { return Deserialize<T>(XmlData, null); } public static T Deserialize<T>(string XmlData, Type[] ExtraTypes) { lock (Locker) { T Result = default(T); try { using (MemoryStream Stream = new MemoryStream()) { using (StreamWriter Writer = new StreamWriter(Stream)) { Writer.Write(XmlData); Writer.Flush(); Stream.Position = 0; XmlSerializer Ser = GetSerializer<T>(ExtraTypes); Result = (T)Ser.Deserialize(Stream); Writer.Close(); } } return Result; } catch (Exception Ex) { throw new Exception("Could not deserialize to " + typeof(T).Name, Ex); } } } public static XDocument Serialize<T>(T Object) { return Serialize<T>(Object, null); } public static XDocument Serialize<T>(T Object, Type[] ExtraTypes) { lock (Locker) { XDocument Xml = null; try { using (MemoryStream stream = new MemoryStream()) { XmlSerializerNamespaces ns = new XmlSerializerNamespaces(); ns.Add("", ""); using (StreamReader Reader = new StreamReader(stream)) { XmlSerializer Serializer = GetSerializer<T>(ExtraTypes); var settings = new XmlWriterSettings { Indent = true }; using (var w = XmlWriter.Create(stream, settings)) { Serializer.Serialize(w, Object, ns); w.Flush(); stream.Position = 0; } Xml = XDocument.Load(Reader, LoadOptions.None); foreach (XElement Ele in Xml.Root.Descendants()) { PropertyInfo PI = typeof(T).GetProperty(Ele.Name.LocalName); if (PI != null && PI.IsDefined(typeof(XmlCommentAttribute), false)) Xml.AddFirst(new XComment(PI.Name + ": " + PI.GetCustomAttributes(typeof(XmlCommentAttribute), false).Cast<XmlCommentAttribute>().Single().Value)); } Reader.Close(); } } return Xml; } catch (Exception Ex) { throw new Exception("Could not serialize from " + typeof(T).Name + " to xml string", Ex); } } } } [AttributeUsage(AttributeTargets.Property, AllowMultiple = false)] public class XmlCommentAttribute : Attribute { public string Value { get; set; } }