您的位置:首页 > 其它

XmlSerializer 构造函数的性能问题

2012-06-21 09:15 232 查看
关键字:XmlSerializer, Performace Issue

近日在解决一个性能问题时,发现如下这段代码的执行要花费较长的时间

SuperElement = XElement.Parse(xmlcontent from resource file);
// 获取指定的内容
IEnumerable<XElement> elements= SuperElement.Descendants().Where(
elem => elem.Name =="Element Name" &&
elem.Attribute("Target") != null);

//ObjectA就是要进行反序列化的类名
m_objectList = newList<ObjectA>();

// 遍历,然后逐一进行反序列化
int logCounter = 1;
foreach (XElement element inelements)
{
System.Diagnostics.Trace.TraceInformation("deserialize2.{0} begin", logCounter);
ObjectAobj = ObjectASerializer<ObjectA>.LoadFromXElement(element);
System.Diagnostics.Trace.TraceInformation("deserialize  2.{0} end", logCounter++);
m_objectList.Add(obj);
}


通过使用DebugViewer查看,发现上面加log之间的的代码占用了较长的时间,代码实现如下

public static TLoadFromXElement(XElement element)
{
int logCounter = 0;

T serializableObject = null;
Type ObjectType = typeof(T);

XmlRootAttribute rootAttr = newXmlRootAttribute();
rootAttr.ElementName =element.Name.ToString();
rootAttr.IsNullable = true;

System.Diagnostics.Trace.TraceInformation("LoadFromXElement Beforector {0}", logCounter++);

XmlSerializer xmlSerializer = newXmlSerializer(ObjectType, rootAttr);

System.Diagnostics.Trace.TraceInformation("LoadFromXElementAfter ctor {0}", logCounter++);

using (XmlReader xmlReader =element.CreateReader())
{
System.Diagnostics.Trace.TraceInformation("LoadFromXElement -before des {0}", logCounter++);

serializableObject =xmlSerializer.Deserialize(xmlReader) as T;
}

System.Diagnostics.Trace.TraceInformation("LoadFromXElement afterdes");

return serializableObject;
}


最终发现上面加log的两行代码占用了较多时间,通过查阅一些资料发现,XmlSerializer在实例化时会根据其构造函数中的Type参数产生临时的assemblies来进行序列化或者反序列化的工作,从来提高效率,但是如果构造函数选用的不当,就会有内存泄露和性能问题。当使用下面的构造函数时,.NET会重用临时产生的assemblies

XmlSerializer.XmlSerializer(Type)

XmlSerializer.XmlSerializer(Type,String)

但是,如果使用其他的构造函数则会生成同一个临时assembly的多个不同版本,即第一次调用XmlSerializer的构造函数时临时生产一个版本的assemblyA,第二次调用XmlSerializer的构造函数时会生成A的另一个版本,第三次调用XmlSerializer的构造函数时会生成A的第三个版本。。。而之前生成的临时版本还不会被卸载,从而就导致了内存泄露和性能问题

上面的代码使用了XmlSerializer(Type,XmlRootAttribute)构造函数,所以才导致了性能问题

详细说明参见XmlSerializer Class in MSDN,内容摘录如下:

Dynamically GeneratedAssemblies

Toincrease performance, the XML serialization infrastructure dynamically generatesassemblies to serialize and deserialize specified types. The infrastructurefinds and reuses those assemblies. This behavior occurs only when using thefollowing constructors:

XmlSerializer.XmlSerializer(Type)

XmlSerializer.XmlSerializer(Type, String)

Ifyou use any of the other constructors, multiple versions of the same assemblyare generated and never unloaded, which results in a memory leak and poorperformance. The easiest solution is to use one of the previously mentioned twoconstructors. Otherwise,
you must cache the assemblies in a
Hashtable

解决办法:

使用Dictionary将第一次实例化的XmlSerializer对象存起来,使用其构造函数的参数作为Key,以后再对同样的Type实例化XmlSerializer时直接从Dictionary中取,改进后的代码

private static readonlyDictionary<string, XmlSerializer> cacheSerializer = newDictionary<string, XmlSerializer>();

public static XmlSerializerGetSerializer(Type type, XmlRootAttribute rootAttr)
{
var key = string.Format("{0}:{1}",type, rootAttr.ElementName);

XmlSerializer serializer;
if(!cacheSerializer.TryGetValue(key, out serializer))
{
serializer = newXmlSerializer(type, rootAttr);
cacheSerializer.Add(key,serializer);
}

return serializer;
}


使用

XmlSerializerxmlSerializer = new XmlSerializer(ObjectType, rootAttr);

// 按照如下方式使用

XmlSerializerxmlSerializer = GetSerializer(ObjectType, rootAttr);

这样就大大提升了性能

参考链接:

http://www.damirscorner.com/XmlSerializerConstructorPerformanceIssues.aspx

http://blogs.msdn.com/b/crm/archive/2009/02/02/boost-performance-with-pre-generated-xmlserializers.aspx

http://mikehadlow.blogspot.com/2006/11/playing-with-xmlserializer.html

Playing with the XmlSerializer
XmlSerializer Performance Issue when SpecifyingXmlRootAttribute













                                            
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: