XmlSerializer带来的性能问题及解决办法
(本文中的思路、二元hashtable等,大力感谢Leo Chen的帮助!)
对于XmlSerializer带来的内存占用过高,最终导致Out Of Memory的问题,参见以前这个链接:http://www.cnblogs.com/juqiang/archive/2008/01/15/1039936.html
(但是那篇文章中对于XmlSerializer构造方法的说明,是错误的。那段代码没有问题,有问题的是下面的)
首先看System.Xml.Serialization.XmlSerializer的构造方法,一共分为三大类:
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来做。代码修改如下:
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));
}
}
经过修改、编译、发布,再次测试,问题得到了解决,哈哈!!!
本文中的思路、二元hashtable等,大力感谢Leo Chen的帮助!
对于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
}

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

这里的二元Hashtable,是从XmlSerializer里面扒出来的,稍微修改了一下而已:































以及:


























经过修改、编译、发布,再次测试,问题得到了解决,哈哈!!!
本文中的思路、二元hashtable等,大力感谢Leo Chen的帮助!
分类:
Troubleshooting
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· 展开说说关于C#中ORM框架的用法!
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?