1

我的代码使用了许多字典,我在从所有字典中释放内存时遇到了问题。当我使用我在这个答案中学到的东西进行调查时,我看到 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));

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

没有 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.
4

3 回答 3

2

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

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

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.
于 2012-10-20T13:34:40.440 回答
0

好吧,您并没有通过这样做来释放内存

value = null;

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

GC.Collect();

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

于 2012-10-20T13:35:09.207 回答
0

从文档中GC.GetTotalMemory

If the forceFullCollection parameter is true, this method waits a short interval before returning while the system collects garbage and finalizes objects. The duration of the interval is an internally specified limit determined by the number of garbage collection cycles completed and the change in the amount of memory recovered between cycles. The garbage collector does not guarantee that all inaccessible memory is collected.

So, there is no bug, GC is nondeterministic, you cannot rely on GetTotalMemory(true) will clean up everything.

You'd need to call GC.Collect() for doing full garbage collection.

于 2012-10-20T13:35:21.750 回答