阅读文章

XmlSerializer带来的性能问题及解决办法

[日期:2008-03-12] 来源:  作者: [字体: ]

     对于XMLSerializer带来的内存占用过高,最终导致Out Of Memory的问题,参见以前这个链接:http://www.cnblogs.com/juqiang/archive/2008/01/15/1039936.HTML
  (但是那篇文章中对于XMLSerializer构造方法的说明,是错误的。那段代码没有问题,有问题的是下面的)
  
  首先看System.XML.Serialization.XMLSerializer的构造方法,一共分为三大类:
  
  public XMLSerializer(Type type) : this(type, (string) null)
  public XMLSerializer(Type type, string defaultNamespace)
  这两个方法,采用了上文引用的那篇文章的处理方式,应用了cache,这是正确的,不会造成内存占用过高。(上文引用那篇文章里面这个地方解释错了)
  
  另一大类的方法是:
  public XMLSerializer(XMLTypeMapping XMLTypeMapping),这个方法里面会产生一个tempAssembly,但是没有用缓存方式来处理。
  
  
  
  有问题的一类方法是:
  public XMLSerializer(Type type, Type[] extraTypes) : this(type, null, extraTypes, null, null, null, null)
  public XMLSerializer(Type type, XMLAttributeOverrides overrides) : this(type, overrides, new Type[0], null, null, null, null)
  public XMLSerializer(Type type, XMLRootAttribute root) : this(type, null, new Type[0], root, null, null, null)
  public XMLSerializer(Type type, XMLAttributeOverrides overrides, Type[] extraTypes, XMLRootAttribute root, string defaultNamespace) : this(type, overrides, extraTypes, root, defaultNamespace, null, null)
  public XMLSerializer(Type type, XMLAttributeOverrides overrides, Type[] extraTypes, XMLRootAttribute root, string defaultNamespace, string location, Evidence evidence)
  前4个都最终调用了最后一个构造方法,里面产生了一个tempAssembly,也没有用缓存方式来护理。
  
  我上次提到的那个问题,问题代码如下:
  public static TReturn Convert<TReturn, TInput>(TInput input) where TReturn: class, new() where TInput: IProvisioningObject
  {
   using (MemoryStream stream = new MemoryStream())
   {
   new XMLSerializer(typeof(TInput)).Serialize((Stream) stream, input);
   stream.Position = 0L;
   XMLSerializer serializer = new XMLSerializer(typeof(TReturn), new XMLRootAttribute(input.GetType().Name));
   return (TReturn) serializer.Deserialize(stream);
   }
  }
  注意红色的代码,这里产生了一个tempAssembly,没有做缓存。这里的核心问题在于,tempAssembly不会被自动释放掉,除非appdomain被unload。
  修正的方式类似于XMLSerializer的处理方式,采用一个二元Hashtable来做。代码修改如下:
   1 private static TempXMLSerializerCache cache = new TempXMLSerializerCache();
   2
   3 public static TReturn Convert<TReturn, TInput>(TInput input)
   4 where TReturn : class, new()
   5 where TInput : IProvisioningObject
   6 {
   7 using (MemoryStream stream = new MemoryStream())
   8 {
   9 new XMLSerializer(typeof(TInput)).Serialize((Stream)stream, input);
  10 stream.Position = 0L;
  11
  12 XMLSerializer serializer = cache[typeof(TReturn).ToString(), input.GetType().Name];
  13 if (serializer == null)
  14 {
  15 lock (cache)
  16 {
  17 serializer = cache[typeof(TReturn).ToString(), input.GetType().Name];
  18 if (serializer == null)
  19 {
  20 serializer = new XMLSerializer(typeof(TReturn), new XMLRootAttribute(input.GetType().Name));
  21 cache.Add(typeof(TReturn).ToString(), input.GetType().Name, serializer);
  22 }
  23 }
  24 }
  25 return (TReturn)serializer.Deserialize(stream);
  26 }
  27 }
  
  这里的二元Hashtable,是从XMLSerializer里面扒出来的,稍微修改了一下而已:
  
   public class TempXMLSerializerCache
   {
   private Hashtable cache = new Hashtable();
  
   public void Add(string ns, object o, XMLSerializer serializer)
   {
   XMLSerializerCacheKey key = new XMLSerializerCacheKey(ns, o);
   lock (this)
   {
   if (this.cache[key] != serializer)
   {
   Hashtable hashtable = new Hashtable();
   foreach (object obj2 in this.cache.Keys)
   {
   hashtable.Add(obj2, this.cache[obj2]);
   }
   this.cache = hashtable;
   this.cache[key] = serializer;
   }
   }
   }
  
   public XMLSerializer this[string ns, object o]
   {
   get
   {
   return (XMLSerializer)this.cache[new XMLSerializerCacheKey(ns, o)];
   }
   }
   }
  
  以及:
   public class XMLSerializerCacheKey
   {
   private string ns;
   private object type;
  
   public XMLSerializerCacheKey(string ns, object type)
   {
   this.type = type;
   this.ns = ns;
   }
  
   public override bool Equals(object o)
   {
   XMLSerializerCacheKey key = o as XMLSerializerCacheKey;
   if (key == null)
   {
   return false;
   }
   return ((key.type == this.type) && (key.ns == this.ns));
   }
  
   public override int GetHashCode()
   {
   return (((this.ns != null) ? this.ns.GetHashCode() : 0) ^ ((this.type != null) ? this.type.GetHashCode() : 0));
   }
   }
  
  经过修改、编译、发布,再次测试,问题得到了解决,哈哈!!!  


阅读:
录入:blue1000

评论 】 【 推荐 】 【 打印
上一篇:除了技术外,我们还需要什么?
下一篇:QQ.NET,基于LumaQQ的.NET开源QQ开发包
相关文章      
本文评论
发表评论


点评: 字数
姓名:

  • 尊重网上道德,遵守中华人民共和国的各项有关法律法规
  • 承担一切因您的行为而直接或间接导致的民事或刑事法律责任
  • 本站管理人员有权保留或删除其管辖留言中的任意内容
  • 本站有权在网站内转载或引用您的评论
  • 参与本评论即表明您已经阅读并接受上述条款