今天发现我写的一个C#程序存在内存泄露。查了很久最后发现是我用了XmlSerializer的重载构造函数导致的。
查了才发现,原来早有说明:
动态生成的程序集
为了提高性能,XML 序列化基础结构动态生成程序集,以便对指定类型进行序列化和反序列化。该基础结构将找到并重新使用这些程序集。仅当使用以下构造函数时,才会发生此行为:
如果使用任何其他构造函数,则将生成同一个程序集的多个版本,这些版本始终不予卸载,从而导致内存泄漏和性能低下。最简单的解决方案是使用上面两个构造函数中的一个。否则,必须在 中缓存程序集,
也就是需要用户自己维护XmlSerializer的实例,根据传入的参数来判别是否对应的实例已经存在了,如果存在就直接返回,否则新new 一个XmlSerializer并且缓存该实例。
后来发现XmlSerializerFactory这个类,原本以为它是解决这个问题而出现的,实际测试结果并非如此。
- namespace XmlSerializerMemoryLeaking
- {
- class Program
- {
- static void Main(string[] args)
- {
- var factory = new XmlSerializerFactory();
- var cached1 = factory.CreateSerializer(typeof(Foo));
- var cached2 = factory.CreateSerializer(typeof(Foo));
- Type t1 = cached1.GetType();
- Type t2 = cached2.GetType();
-
- Console.WriteLine(t1);
- Console.WriteLine(t2);
- Console.WriteLine(t1.Assembly);
- Console.WriteLine(t2.Assembly);
- //True
- Console.WriteLine(object.Equals(t1.Assembly, t2.Assembly));
- //True
- Console.WriteLine(object.Equals(t1, t2));
- //True
- Console.WriteLine(object.ReferenceEquals(cached1.GetType(), cached2.GetType()));
- //False
- Console.WriteLine(object.ReferenceEquals(cached1, cached2));
- XmlRootAttribute root = new XmlRootAttribute("foo");
- var serializer1 = factory.CreateSerializer(typeof(Foo), root);
- var serializer2 = factory.CreateSerializer(typeof(Foo), root);
- Type t3 = serializer1.GetType();
- Type t4 = serializer2.GetType();
- Console.WriteLine(t3);
- Console.WriteLine(t4);
- Console.WriteLine(t3.Assembly);
- Console.WriteLine(t4.Assembly);
- //False
- Console.WriteLine(object.Equals(t3.Assembly, t4.Assembly));
- //False
- Console.WriteLine(object.Equals(t3, t4));
- }
- }
- public class Foo { }
- }
运行结果如下:
Insert mode
- Microsoft.Xml.Serialization.GeneratedAssembly.FooSerializer
- Microsoft.Xml.Serialization.GeneratedAssembly.FooSerializer
- vg2v6ou8, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
- vg2v6ou8, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
- True
- True
- True
- False
- Microsoft.Xml.Serialization.GeneratedAssembly.FooSerializer
- Microsoft.Xml.Serialization.GeneratedAssembly.FooSerializer
- hzolh2td, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
- o2nhpo_z, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
- False
- False
- 请按任意键继续. . .
可以看到serializer1和serializer2其实是两个不同程序集中的同名类,这两个程序集是.net framework在运行时动态生成的。
下面这个帖子说明了这个问题:
看来还是得自己维护XmlSerializer的实例才行
阅读(1494) | 评论(0) | 转发(0) |