当我使用该方法反序列化字典时,我有内存泄漏。这里通过以下测试重现问题。
public static Dictionary<TKey, TValue> DeserializeDictionary<TKey, TValue>(this string iSerialization)
{
Dictionary<TKey, TValue> dic;
using (var textWriter = new StringReader(iSerialization))
{
XmlSerializer serializer = new XmlSerializer(typeof(Item<TKey, TValue>[]), new XmlRootAttribute() { ElementName = "items" });
dic = ((Item<TKey, TValue>[])serializer.Deserialize(textWriter)).ToDictionary(i => i.Key, i => i.Value);
textWriter.Close();
}
return dic;
}
public class Item<TKey, TValue>
{
[XmlAttribute]
public TKey Key;
[XmlAttribute]
public TValue Value;
}
测试:
[TestMethod]
public void test()
{
string test = "<?xml version=\"1.0\" encoding=\"utf-16\"?><items xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"><ItemOfStringString Key=\"mykey\" Value=\"myvalue\" /></items>";
while(true)
{
Dictionary<string, string> tesfezf = test.DeserializeDictionary<string, string>();
}
}
你知道问题出在哪里吗?
编辑:我在一个循环(arround 20000)中以workerazure角色使用这个方法,这填补了内存并抛出了内存异常。
答案 0 :(得分:2)
它与反序列化无关,而是与XmlSerializer的实例化无关。此特定构造函数重载生成一个新的临时程序集,该程序集在每次调用时都会在应用程序域中加载,并且永远不会被卸载。最终结果是,如果计划在应用程序域的生命周期中多次使用它,则应缓存XmlSerializer或使用其他构造函数。
您可以使用这段代码对其进行测试,您将看到内存使用量的增加。
var root = new XmlRootAttribute() {ElementName = "items"};
var type = typeof (Item<string, string>[]);
while (true)
{
XmlSerializer serializer = new XmlSerializer(type, root);
GC.Collect();
}
如果将块 XmlSerializer serializer = new XmlSerializer(type,root); 移出代码中的循环,只是在循环中反序列化,则内存保持不变。
以下是大量文章都描述了相同的问题,包括微软网站上的支持文章。
Blog on Msdn - .NET Memory Leak: XmlSerializing your way to a Memory Leak
答案 1 :(得分:0)
据我所知,没有内存泄漏。但是在你的测试用例中存在明显不良的内存使用情况。
CG.Collect()大部分时间都不是迫在眉睫的。特别是当存在非托管资源时,它必须在释放所有不需要的内存之前清除终结队列。
在这种情况下,它会消耗大量内存,并且不允许垃圾收集器完成其最终化过程。
因此,在Deserialize之后,您可以调用GC.Collect()并等待GC完成其最终确定。
//Force garbage collection.
GC.Collect();
// Wait for all finalizers to complete before continuing.
// Without this call to GC.WaitForPendingFinalizers,
// the worker loop below might execute at the same time
// as the finalizers.
// With this call, the worker loop executes only after
// all finalizers have been called.
GC.WaitForPendingFinalizers();
参考: