【问题标题】:c# memory leak on Deserialize dictionaryc#反序列化字典上的内存泄漏
【发布时间】:2015-03-04 19:03:01
【问题描述】:

当我使用该方法反序列化字典时,我有内存泄漏。这里通过下面的测试来重现问题。

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>();
        }

    }

你知道问题出在哪里吗?

编辑:我在一个workerazure角色中使用这个方法,在一个循环中(大约20000),这会填充内存并抛出内存不足异常。

【问题讨论】:

  • 您有什么证据表明存在内存泄漏?
  • 您的测试中没有断言,能否详细说明您断言的问题是什么?
  • 在这种情况下,预计内存使用量会增加,您正在反序列化数据。 CLR 将执行所需的工作,并分配实现它所需的内存。
  • @Julian50 代码使用内存的事实并不意味着它正在泄漏内存。这只是意味着它正在使用大量内存。
  • 预编译或至少缓存的序列化程序应该解决多个动态编译程序集消耗所有内存的问题...stackoverflow.com/questions/678676/…

标签: c# .net dictionary memory-leaks garbage-collection


【解决方案1】:

它与反序列化无关,而是与XmlSerializer 的实例化有关。这个特定的构造函数重载会生成一个新的临时程序集,每次调用都会在应用程序域中加载该程序集,并且永远不会被卸载。最终结果是,如果您计划在应用程序域的生命周期中多次使用 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); 移出代码的循环并在循环中反序列化,则内存保持不变。

这里有很多文章都描述了相同的问题,包括 Microsoft 网站上的支持文章。

Microsoft Support KB 886385

Blog on Msdn - .NET Memory Leak: XmlSerializing your way to a Memory Leak

A Memory Leak brought to you by XmlSerializer

Question and Answer on StackOverflow

【讨论】:

  • 非常感谢。只有这些构造函数适用于我的情况 'XmlSerializer(type) 和 XmlSerializer(type, defaultNameSpace)' 并解决我的问题。我的意思是不要给内存充电。我不知道为什么我的问题被否决了这么多次......无论如何。谢谢你是我的超人;)
  • 很高兴我能帮上忙。我也不知道为什么,但我会 +1 来帮助你。
【解决方案2】:

据我所知,没有内存泄漏。但是您的测试用例中存在明显的不良内存使用情况。

CG.Collect() 在大多数情况下并不是迫在眉睫。特别是当有非托管资源时,它必须在释放所有不需要的内存之前清除终结队列。

在这种情况下,它会消耗大量内存,并且不允许垃圾收集器完成其终结过程。

因此,在反序列化之后,您可以调用 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();

参考:

GC.WaitForPendingFinalizers

GC.WaitForFullGCComplete Method

【讨论】:

    猜你喜欢
    • 2011-04-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-08-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多