无法释放100,000字典<t,u> </t,u>使用的内存

时间:2012-10-20 13:28:34

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

我的代码使用了很多字典,我遇到了从所有字典中释放内存的问题。当我investigate using what I learned in this answer时,我看到GenericEqualityComparer就在那里,我怀疑这就是使用这个内存的原因。

任何人都可以证实这一点,或者告诉我如何释放这段记忆?

代码

        Console.WriteLine("{0,10}: Start Point", GC.GetTotalMemory(true));
        List<string> t1 = new List<string>();
        Console.WriteLine("{0,10}: <------- Create List", GC.GetTotalMemory(true));
        t1 = null;
        Console.WriteLine("{0,10}: <------- null List", GC.GetTotalMemory(true));

        GC.Collect();
        Console.WriteLine("{0,10}: After GC.Collect", GC.GetTotalMemory(true));
        Dictionary<string, string> t2 = new Dictionary<string, string>();
        Console.WriteLine("{0,10}: <------- Create Dict", GC.GetTotalMemory(true));
        t2 = null;
        Console.WriteLine("{0,10}: <------- null Dict", GC.GetTotalMemory(true));


        GC.Collect();
        Console.WriteLine("{0,10}: After GC.Collect", GC.GetTotalMemory(true));
        Dictionary<string, string> t3 = new Dictionary<string, string>();
        Console.WriteLine("{0,10}: <------- Create Dict", GC.GetTotalMemory(true));
        t3 = null;
        Console.WriteLine("{0,10}: <------- null Dict", GC.GetTotalMemory(true));

        GC.Collect();
        Console.WriteLine("{0,10}: After GC.Collect", GC.GetTotalMemory(true));
        Dictionary<string, string> t4 = new Dictionary<string, string>();
        Console.WriteLine("{0,10}: <------- Create Dict", GC.GetTotalMemory(true));
        t4 = null;
        Console.WriteLine("{0,10}: <------- null Dict", GC.GetTotalMemory(true));

        GC.Collect();
        Console.WriteLine("{0,10}: After GC.Collect", GC.GetTotalMemory(true));
        Dictionary<string, string> t5 = new Dictionary<string, string>();
        Console.WriteLine("{0,10}: <------- Create Dict", GC.GetTotalMemory(true));
        t5 = null;
        Console.WriteLine("{0,10}: <------- null Dict", GC.GetTotalMemory(true));

        GC.Collect();
        Console.WriteLine("{0,10}: After GC.Collect", GC.GetTotalMemory(true));
        Dictionary<string, string> t6 = new Dictionary<string, string>();
        Console.WriteLine("{0,10}: <------- Create Dict", GC.GetTotalMemory(true));
        GC.KeepAlive(t6);
        t6 = null;
        Console.WriteLine("{0,10}: <------- null Dict", GC.GetTotalMemory(true));

        GC.Collect();
        Console.WriteLine("{0,10}: <------- End.", GC.GetTotalMemory(true));

注意:我有两个版本的代码。使用GC.Collect进行一次编辑就像在SO上所建议的一样,但这没有任何好处。

没有GC收集的输出

 95884: Start Point
 97872: <------- Create List
 97888: <------- null List
 97952: <------- Create Dict
 97968: <------- null Dict
 98032: <------- Create Dict
 98048: <------- null Dict
 98112: <------- Create Dict
 98128: <------- null Dict
 98192: <------- Create Dict
 98208: <------- null Dict
 98272: <------- Create Dict
 98288: <------- null Dict

使用GC收集输出(根据建议)

 96004: Start Point
 97992: <------- Create List
 98008: <------- null List
 98024: After GC.Collect
 98088: <------- Create Dict
 98104: <------- null Dict
 98120: After GC.Collect
 98184: <------- Create Dict
 98200: <------- null Dict
 98216: After GC.Collect
 98280: <------- Create Dict
 98296: <------- null Dict
 98312: After GC.Collect
 98376: <------- Create Dict
 98392: <------- null Dict
 98408: After GC.Collect
 98472: <------- Create Dict
 98488: <------- null Dict
 98504: <------- End.

在发布模式下输出(根据建议)

 96028: Start Point
 98016: <------- Create List
 98032: <------- null List
 98048: After GC.Collect
 98112: <------- Create Dict
 98128: <------- null Dict
 98144: After GC.Collect
 98208: <------- Create Dict
 98224: <------- null Dict
 98240: After GC.Collect
 98304: <------- Create Dict
 98320: <------- null Dict
 98336: After GC.Collect
 98400: <------- Create Dict
 98416: <------- null Dict
 98432: After GC.Collect
 98496: <------- Create Dict
 98512: <------- null Dict
 98528: <------- End.

在没有GC收集的发布模式下输出(根据建议)

 96028: Start Point
 98016: <------- Create List
 98032: <------- null List
 98096: <------- Create Dict
 98112: <------- null Dict
 98176: <------- Create Dict
 98192: <------- null Dict
 98256: <------- Create Dict
 98272: <------- null Dict
 98336: <------- Create Dict
 98352: <------- null Dict
 98416: <------- Create Dict
 98432: <------- null Dict
 98448: <------- End.

3 个答案:

答案 0 :(得分:2)

在调试模式下,GC 不会在当前方法范围中收集对象,因为对它们的引用仍然存在。尝试构建它以进行发布,无需调试即可运行并检查结果。

在调试模式下打印为true但在发布时为false的代码:

object obj = new object();
WeakReference reference = new WeakReference(obj);
GC.Collect(0, GCCollectionMode.Forced);
Console.WriteLine(reference.IsAlive);

从OP编辑:调试模式确实会使内存使用量人为增加。当我运行独立应用程序时,我得到了这个输出。谢谢,我接受了这个答案。

 21852: Start Point
 29328: <------- Create List
 29328: <------- null List
 29328: <------- Create Dict
 29328: <------- null Dict
 29328: <------- Create Dict
 29328: <------- null Dict
 29328: <------- Create Dict
 29328: <------- null Dict
 29328: <------- Create Dict
 29328: <------- null Dict
 29376: <------- Create Dict
 29328: <------- null Dict
 29328: <------- End.

答案 1 :(得分:0)

嗯,你不是通过做

来释放记忆
value = null;

您只是将值设置为null,而不是从内存中删除某些内容。 未明确请求垃圾收集器执行其任务。

GC.Collect();

执行任务需要什么。你通常不这样做,因为GC编写得很好,并选择自己的时间来收集未使用的对象。如果你无缘无故地调用它,它也会对你的表现造成很大影响。关于GC如何以及为什么收集某些东西的条件,还有一系列条件。调试,方法,范围等。

答案 2 :(得分:0)

来自GC.GetTotalMemory的文档:

  

如果forceFullCollection参数为true,则此方法等待a   系统收集垃圾时返回前的短暂间隔   完成对象。间隔的持续时间是内部的   指定的限制由垃圾收集周期数决定   完成并恢复之间恢复的内存量   周期。垃圾收集器不保证所有无法访问   收集记忆。

所以,没有错误,GC是不确定的,你不能依赖GetTotalMemory(true)来清理所有东西。

您需要调用GC.Collect()进行完整的垃圾回收。