Chinaunix首页 | 论坛 | 博客
  • 博客访问: 42986
  • 博文数量: 6
  • 博客积分: 1445
  • 博客等级: 上尉
  • 技术积分: 90
  • 用 户 组: 普通用户
  • 注册时间: 2007-03-26 22:18
文章分类

全部博文(6)

文章存档

2012年(1)

2011年(1)

2009年(2)

2008年(2)

我的朋友
最近访客

分类: 嵌入式

2012-06-25 16:49:14

今天发现我写的一个C#程序存在内存泄露。查了很久最后发现是我用了XmlSerializer的重载构造函数导致的。
查了才发现,原来早有说明:

动态生成的程序集

为了提高性能,XML 序列化基础结构动态生成程序集,以便对指定类型进行序列化和反序列化。该基础结构将找到并重新使用这些程序集。仅当使用以下构造函数时,才会发生此行为:

如果使用任何其他构造函数,则将生成同一个程序集的多个版本,这些版本始终不予卸载,从而导致内存泄漏和性能低下。最简单的解决方案是使用上面两个构造函数中的一个。否则,必须在  中缓存程序集,

也就是需要用户自己维护XmlSerializer的实例,根据传入的参数来判别是否对应的实例已经存在了,如果存在就直接返回,否则新new 一个XmlSerializer并且缓存该实例。

后来发现XmlSerializerFactory这个类,原本以为它是解决这个问题而出现的,实际测试结果并非如此。


点击(此处)折叠或打开

  1. namespace XmlSerializerMemoryLeaking
  2. {
  3.     class Program
  4.     {
  5.         static void Main(string[] args)
  6.         {
  7.             var factory = new XmlSerializerFactory();

  8.             var cached1 = factory.CreateSerializer(typeof(Foo));
  9.             var cached2 = factory.CreateSerializer(typeof(Foo));

  10.             Type t1 = cached1.GetType();
  11.             Type t2 = cached2.GetType();
  12.             
  13.             Console.WriteLine(t1);
  14.             Console.WriteLine(t2);
  15.             Console.WriteLine(t1.Assembly);
  16.             Console.WriteLine(t2.Assembly);

  17.             //True
  18.             Console.WriteLine(object.Equals(t1.Assembly, t2.Assembly));
  19.             //True
  20.             Console.WriteLine(object.Equals(t1, t2));
  21.             //True
  22.             Console.WriteLine(object.ReferenceEquals(cached1.GetType(), cached2.GetType()));
  23.             //False
  24.             Console.WriteLine(object.ReferenceEquals(cached1, cached2));

  25.             XmlRootAttribute root = new XmlRootAttribute("foo");
  26.             var serializer1 = factory.CreateSerializer(typeof(Foo), root);
  27.             var serializer2 = factory.CreateSerializer(typeof(Foo), root);

  28.             Type t3 = serializer1.GetType();
  29.             Type t4 = serializer2.GetType();

  30.             Console.WriteLine(t3);
  31.             Console.WriteLine(t4);
  32.             Console.WriteLine(t3.Assembly);
  33.             Console.WriteLine(t4.Assembly);

  34.             //False
  35.             Console.WriteLine(object.Equals(t3.Assembly, t4.Assembly));
  36.             //False
  37.             Console.WriteLine(object.Equals(t3, t4));
  38.         }
  39.     }
  40.     public class Foo { }
  41. }
运行结果如下:

点击(此处)折叠或打开

  1. Microsoft.Xml.Serialization.GeneratedAssembly.FooSerializer
  2. Microsoft.Xml.Serialization.GeneratedAssembly.FooSerializer
  3. vg2v6ou8, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
  4. vg2v6ou8, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
  5. True
  6. True
  7. True
  8. False
  9. Microsoft.Xml.Serialization.GeneratedAssembly.FooSerializer
  10. Microsoft.Xml.Serialization.GeneratedAssembly.FooSerializer
  11. hzolh2td, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
  12. o2nhpo_z, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
  13. False
  14. False
  15. 请按任意键继续. . .
可以看到serializer1和serializer2其实是两个不同程序集中的同名类,这两个程序集是.net framework在运行时动态生成的。
下面这个帖子说明了这个问题:

看来还是得自己维护XmlSerializer的实例才行
阅读(1494) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~