我创建了一个c#应用程序,它使用了150 mb的内存(私有字节),主要是由于一个大字典:
Dictionary<string, int> Txns = new Dictionary<string, int>();
我在想怎么释放这段记忆。我试过了:
Txns = null;
GC.Collect();
但这似乎并没有对我的私人字节产生多大影响--它们从155 mb下降到145 mb。
谢谢
- 编辑-
好吧,我有更多的运气与此代码(它得到的私人字节下降到50 mb),但为什么?
Txns.Clear(); // <- makes all the difference
Txns = null;
GC.Collect();
- 编辑-
好吧,对于每个说“不要使用GC. collect”的人来说,这很公平(我不打算争论这一点,除了说你可以看到我的C背景),但它并没有真正回答我的问题:为什么垃圾收集器只在我先清除事务列表的情况下才释放内存呢?既然字典已经被取消引用了,它不应该释放内存吗?
8条答案
按热度按时间xoefb8l81#
私有字节反映了进程的内存使用情况。当对象被收集时,相关的内存段可能会也可能不会被释放给操作系统。CLR在操作系统级别管理内存,由于分配和释放内存不是免费的,因此没有理由立即释放每一块内存,因为应用程序可能会在以后请求更多内存。
ffx8fchx2#
如果你调用
GC.Collect()
,它会开始工作,但会立即返回而不是阻塞,所以你看不到任何效果。如果你只是调用GC.WaitForPendingFinalizers()
,它会阻塞你的应用,直到GC.Collect()
完成它的工作。lyfkaqu13#
很可能你在别的地方有一个对字典的隐藏引用。因此字典没有被收集,但是如果你
Clear()
它,内容就被收集了。正如其他人已经注意到的,不推荐强制GC,这可能会导致内存被推到更高的“代”中,而这些“代”不经常被收集,从而浪费的内存比长期获得的内存更多。
du7egjpx4#
从内存中不确定
Dictionary
是否有Dispose()
,但它肯定有Clear()
。在设置任何对null
的引用之前,调用其中任何一个。然后,让垃圾收集器完成它的工作。自己显式调用
GC.Collect()
几乎从来都不是一个好主意,它甚至可能不做你想要/需要/期望的事情,最终会消耗你的性能。静态代码分析(=FxCop)不会无缘无故地用Reliability rule CA2001警告你,你知道吗?除非你真的知道你在做什么,否则就不要做这件事。即使这样也不要做。- )你确定字典有那么大吗?它不就是10 Mb的内存吗,其余的都被你的应用程序占用了吗?这个问题可能对你有帮助:您是否使用过分析器来查看内存实际消耗的位置...?
41ik7eoe5#
编辑:
公平地说,将引用设置为null并不会释放内存,它会将其容器分配给不同的地址,在本例中为null。根据MSDN,调用
Clear()
,会这样做:“计数”属性设置为0,同时也释放对集合元素中其他对象的引用。容量保持不变。...
您不应该调用垃圾回收器。您正在使用没有本机资源的托管对象,请相信垃圾回收器会在您之后进行清理。
除了字典的大小之外,你不需要担心内存,内存不是你的问题,它是垃圾收集器的问题。
调用
Clear()
将删除对其中包含的任何对象的引用,但容量保持不变。从技术上讲,收集内存是昂贵的,并且是一个相当耗时的操作。原因是,GC不仅处理堆内存并清理堆,它还对堆进行碎片整理。它试图将内存移动到连续的块中,以便在某些代码发出大请求时加速分配。
你的字典有多大,你使用155MB的内存?
o2g1uqev6#
你需要内存吗?内存是可用的,只是没有被回收。你不应该清除字典,对它持有一个weak reference,让运行时做它的工作。
如果你想真正深入地了解发生了什么,请查看.NET Memory Profiler。这将给予你能够准确地了解对象发生了什么,它是什么代,什么东西正在使用什么内存等等。:)
vvppvyoh7#
好吧,我有一个理论... Dictionary是KeyValuePair的集合,它也是一个引用类型。
您的字典包含这些keyValuePairs。当您说:
它从这些KeyValuePair集合中释放引用“Txns”。但这些KeyValuePair仍在引用150 Mb的实际内存,并且它们在范围内,因此未准备好进行垃圾收集。
但是当你使用以下命令时:
在这里,clear方法还从它们各自的KeyValuePair对象引用中释放了150Mb的数据。因此,这些对象已经准备好进行垃圾收集。
这只是我在这里做的一个大胆的猜测。欢迎评论:)
bvn4nwqk8#
Windows有两个内存可用性事件。我希望CLR对此做出响应。如果有足够的内存可用,明智的做法是不运行垃圾收集器。因此,为了确保您确实观察到了错误的CLR行为,请使用另一个使用大量内存的虚拟应用程序重复此测试。