C# 在c中显式释放内存#

C# 在c中显式释放内存#,c#,.net,memory,memory-leaks,profiling,C#,.net,Memory,Memory Leaks,Profiling,我创建了一个c#应用程序,它使用了150mb的内存(专用字节),主要是因为有一个大字典: Dictionary<string, int> Txns = new Dictionary<string, int>(); 但它似乎并没有对我的私有字节造成太大的影响——它们从155mb下降到145mb。 有什么线索吗 谢谢 -编辑- 好吧,我在这段代码中运气更好(它将私有字节减少到50mb),但是为什么呢 Txns.Clear(); // <- makes all the

我创建了一个c#应用程序,它使用了150mb的内存(专用字节),主要是因为有一个大字典:

Dictionary<string, int> Txns = new Dictionary<string, int>();
但它似乎并没有对我的私有字节造成太大的影响——它们从155mb下降到145mb。 有什么线索吗

谢谢

-编辑-

好吧,我在这段代码中运气更好(它将私有字节减少到50mb),但是为什么呢

Txns.Clear(); // <- makes all the difference
Txns = null;
GC.Collect();

Txns.Clear();// 无法从内存中确定
字典是否有
Dispose()
,但它肯定有
Clear()
。在将任何引用设置为
null
之前调用其中一个

然后,简单地让垃圾收集器完成它的工作。自己显式地调用
GC.Collect()
几乎从来都不是一个好主意,它甚至可能不会做您想要/需要/期望的事情,最终会降低性能。静态代码分析(=FxCop)不会无缘无故地警告您,您知道吗?除非你真的知道自己在做什么,否则不要这样做。即使这样,也不要这样做


你确定这本字典有那么大吗?它不是只有10MB的内存,其余的由应用程序占用吗?可能对您有所帮助的问题:您是否使用了探查器来查看内存的实际消耗位置…?

尝试强制GC通常不是一个好主意。你真的需要把整个字典都放在内存中吗?

如果你调用GC.Collect()它开始工作,但它立即返回,它不会阻塞,所以你看不到它的影响,如果你只调用GC.WaitForPendingFinalizers(),它会阻塞你的应用,直到GC.Collect()为止完成它的工作

很可能你在其他地方隐藏了对字典的引用。因此,不会收集字典,但如果您
Clear()
it,则会收集内容

正如其他人已经指出的,不建议强制GC。这可能会导致内存被推到不经常收集的更高“代”中,从而浪费比长期获得的内存更多的内存。

编辑:

公平地说,将引用设置为null并不会释放内存,它会将其容器分配给不同的地址,在本例中为null。根据,调用
Clear()
,会执行以下操作:“Count属性设置为0,并且也会释放对集合元素中其他对象的引用。容量保持不变。”

你不应该给垃圾收集器打电话。如果您使用的是没有本机资源的托管对象,请相信垃圾收集器会在您使用后进行清理

除了字典的大小,你不需要担心内存,内存不是你的问题,而是垃圾收集器的问题

调用
Clear()
将删除对其中任何包含对象的引用,但容量保持不变

从技术上讲,收集内存是昂贵的,并且是相当耗时的操作。原因是,GC不仅处理堆内存并清理堆,还对堆进行碎片整理。它尝试将内存移动到连续的块中,以便在某些代码发出较大请求时加快分配


p、 您使用155MB内存的字典有多大?

专用字节反映了进程的内存使用情况。收集对象时,相关内存段可能会释放到操作系统,也可能不会释放到操作系统。CLR在操作系统级别管理内存,由于分配和释放内存不是空闲的,因此没有理由立即释放每一块内存,因为应用程序以后可能会请求更多内存

Windows有两个内存可用性事件。我希望CLR对此做出回应。如果有足够的内存可用,明智的做法是不运行垃圾收集器。因此,为了确保您确实观察到了错误的CLR行为,请使用另一个使用大量内存的虚拟应用程序重复此测试。

您需要回内存吗?内存是可用的,只是没有被回收。您不应该清除字典,保留一个字典,让运行时完成它的工作


如果你想真正深入地了解正在发生的事情,请查看。这将使您能够准确地了解对象发生了什么,对象是哪一代,哪些对象正在使用哪些内存,等等。:)

好吧,我有一个理论。。。 Dictionary是KeyValuePair的集合,也是一种引用类型

您的字典包含这些keyValuePairs。当你说:

Txns = null
它将引用“Txns”从那些KeyValuePair集合中释放出来。但是这些KeyValuePair仍然引用了150MB的实际内存,并且它们在范围内,因此还没有准备好进行垃圾收集

但当您使用以下选项时:

Txns.Clear();
Txns = null;
GC.Collect();
在这里,clear方法还从各自的KeyValuePair对象引用中释放150Mb的数据。因此,这些对象已准备好进行垃圾收集


我只是在胡乱猜测。欢迎评论:)

GC.Collect()不强制要求在当时收集所有可以收集的内存,因为垃圾收集是一个多步骤的过程。我可能会补充一个过程,您通常甚至不需要知道有关的详细信息……是否有必要将Txns设置为null,这会有什么不同吗?或者仅仅清除内容就足够(释放内存)?哎呀!甚至不能开始考虑周期性地(而且经常是:它每秒尝试两次!)调用GC.Collect然后等待所有挂起的终结器的线程的不良程度。您是否对扩展应用程序完全不感兴趣?那只是想掩盖一个不好的症状,糟透了!我想我只能在这里-1…@peSHIr:同意,不过为了公平起见,它确实明确地回答了这个问题。好主意与否是另一个问题。@andy:勉强同意。那么我应该-1这个问题来代替。。。?也似乎不必要的苛刻和无用。哦,好吧,我不是苏尔
Txns.Clear();
Txns = null;
GC.Collect();