XmlSerializer 构造函数的性能问题

本文探讨了使用XmlSerializer时遇到的性能问题,特别是当使用特定构造函数时可能导致内存泄露和性能下降。通过分析,发现XmlSerializer(Type, XmlRootAttribute)构造函数是问题所在。解决方案是利用Dictionary缓存已实例化的XmlSerializer对象,避免多次生成临时assembly,从而提高性能。" 139051267,17243493,Grafana在AI系统监控中的应用与实战,"['AI', '大数据', '监控', 'Grafana', 'InfluxDB', '时间序列数据库']

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

关键字: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














                
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值