在 C# 中显式释放内存
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/823661/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Explicitly freeing memory in c#
提问by Chris
I've create a c# application which uses up 150mb of memory (private bytes), mainly due to a big dictionary:
我创建了 ac# 应用程序,它使用了 150mb 的内存(私有字节),主要是由于一个大字典:
Dictionary<string, int> Txns = new Dictionary<string, int>();
I was wondering how to free this memory up. I've tried this:
我想知道如何释放这个内存。我试过这个:
Txns = null;
GC.Collect();
But it doesn't seem to make much of a dent in my private bytes - they drop from say 155mb to 145mb. Any clues?
但这似乎对我的私人字节没有太大影响 - 它们从 155mb 下降到 145mb。有什么线索吗?
Thanks
谢谢
-edit-
-编辑-
Okay I'm having more luck with this code (it gets the private bytes down to 50mb), but why?
好的,我对这段代码有更多的运气(它将私有字节降低到 50mb),但为什么呢?
Txns.Clear(); // <- makes all the difference
Txns = null;
GC.Collect();
-edit-
-编辑-
Okay for everyone who says 'don't use GC.collect', fair enough (I'm not going to debate that, other than saying you can see my C background coming through), but it doesn't really answer my question: Why does the garbage collector only free the memory if i clear the transaction list first? Shouldn't it free the memory anyway, since the dictionary has been dereferenced?
好吧,对于那些说“不要使用 GC.collect”的人来说,这很公平(我不打算争论这个,除了说你可以看到我的 C 背景知识),但它并没有真正回答我的问题:为什么垃圾收集器只在我先清除事务列表时才释放内存?既然字典已被取消引用,它不应该释放内存吗?
采纳答案by Brian Rasmussen
Private bytes reflect the process' memory usage. When objects are collected the associated memory segment may or may not be freed to the OS. The CLR manages memory at the OS level and since allocating and freeing memory isn't free there's no reason to free each piece of memory immediately as chances are that the application will probably request more memory later.
私有字节反映了进程的内存使用情况。当对象被收集时,相关的内存段可能会或可能不会释放给操作系统。CLR 在操作系统级别管理内存,并且由于分配和释放内存不是免费的,因此没有理由立即释放每块内存,因为应用程序稍后可能会请求更多内存。
回答by peSHIr
Not sure from memory if Dictionary
has a Dispose()
or not, but it's bound to have a Clear()
. Call either of these before setting any references to null
.
从记忆中不确定是否Dictionary
有一个Dispose()
,但它肯定有一个Clear()
. 在将任何引用设置为null
.
Then, simply let the garbage collector do its work. It is almost nevera good idea to call GC.Collect()
explicitly yourself and it might not even do what you want/need/expect and end up costing you performance. Static Code Analysis (=FxCop) doesn't warn you with Reliability rule CA2001about this for nothing, you know? Simply do not do this unless you really know what you're doing. And even then don't do it. ;-)
然后,简单地让垃圾收集器完成它的工作。明确地调用自己几乎从来都不是一个好主意GC.Collect()
,它甚至可能不会做你想要/需要/期望的事情,最终会降低你的性能。静态代码分析 (=FxCop) 不会用可靠性规则 CA2001就此向您发出警告,您知道吗?除非你真的知道你在做什么,否则不要这样做。即使那样也不要这样做。;-)
Are you sure the dictionary is that huge? Isn't it just 10 Mb of memory and the rest is otherwise taken by your application? Question that might help you: Have you used a profiler yet to see where memory is actually consumed...?
你确定字典有那么大吗?不是只有 10 Mb 的内存,其余的都由您的应用程序占用吗?可能对您有帮助的问题:您是否使用过分析器来查看实际消耗内存的位置...?
回答by ivmos
It's not usually a good idea trying to force the GC. Do you really need to have the whole dictionary in memory?
试图强制执行 GC 通常不是一个好主意。你真的需要在内存中保存整个字典吗?
回答by Sadegh
if u call GC.Collect() it start to do its job , but it returns immediately, it doesnt block, so you dont see its affect, if you just call GC.WaitForPendingFinalizers() after that it will block your app until GC.Collect() finish its job
如果你调用 GC.Collect() 它开始做它的工作,但它会立即返回,它不会阻塞,所以你看不到它的影响,如果你只是在调用 GC.WaitForPendingFinalizers() 之后它会阻塞你的应用程序直到 GC。 Collect() 完成它的工作
回答by David Schmitt
Most probably you have a hidden reference to the dictionary somewhere else. Thus the dictionary is not collected, but if you Clear()
it, the contents get collected.
很可能您在其他地方隐藏了对字典的引用。因此,字典不会被收集,但如果你Clear()
这样做,内容就会被收集。
As others have already noted, forcing the GC is not recommended. This might lead to memory being pushed into higher "generations" which are not often collected, thereby wasting more memory than gained in the long run.
正如其他人已经指出的那样,不建议强制执行 GC。这可能会导致内存被推到更高的“代”中,而这些“代”通常不会被收集,从而从长远来看浪费的内存多于获得的内存。
回答by Chris
Edit:
编辑:
To be fair, setting the reference to null does not free the memory, it assigns it's container to a different address, in this case null. According to MSDN, calling Clear()
, does this: "The Count property is set to 0, and references to other objects from elements of the collection are also released. The capacity remains unchanged."
公平地说,将引用设置为 null 不会释放内存,而是将其容器分配给不同的地址,在这种情况下为 null。根据MSDN,调用Clear()
,这样做:“Count 属性设置为 0,并且从集合的元素到其他对象的引用也被释放。容量保持不变。”
...
...
You should never call the garbage collector. You are using managed objects with no native resources, trust the garbage collector to clean up after you.
你永远不应该调用垃圾收集器。您正在使用没有本机资源的托管对象,请相信垃圾收集器会在您之后进行清理。
Besides the size of your dictionary, you don't need to worry about memory, memory isn't your problem, it's garbage collectors problem.
除了字典的大小之外,您无需担心内存,内存不是您的问题,而是垃圾收集器的问题。
Calling Clear()
will remove the references to any contained object inside, but the capacity remains unchanged.
调用Clear()
将删除对内部任何包含对象的引用,但容量保持不变。
On a technical note, collecting memory is expensive and a considerable time consuming operating. Reason being, not only does the GC handle heap memory and clean up your heap, it also sort of defrags the heap. It tries to move memory into contiguous blocks to speed up allocation for when some piece of code makes a large request.
从技术上讲,收集内存很昂贵,而且操作相当耗时。原因是,GC 不仅会处理堆内存并清理您的堆,还会对堆进行碎片整理。它会尝试将内存移动到连续的块中,以在某段代码发出大请求时加快分配速度。
p.s. How big is your dictionary that you use 155MB of memory?
ps 你用155MB内存的字典有多大?
回答by MSalters
Windows has two memory availability events. I'd expect the CLR to respond to this. If there's plenty of memory available, the smart thing is to NOT run the garbage collector. So, to make sure that you are indeed observing bad CLR behavior, please repeat this test with another dummy application using a big heap of memory.
Windows 有两个内存可用性事件。我希望 CLR 对此做出回应。如果有足够的内存可用,明智的做法是不要运行垃圾收集器。因此,为了确保您确实观察到不良的 CLR 行为,请使用另一个使用大量内存的虚拟应用程序重复此测试。
回答by JP Alioto
Do you need the memory back? The memory is available, it's just not being reclaimed. You should not clear the dictionary, hold a weak referenceto it and let the runtime do its job.
你需要恢复记忆吗?内存可用,只是没有被回收。你不应该清除字典,持有对它的弱引用并让运行时完成它的工作。
If you want to see really deep into what's going on, check out the .NET Memory Profiler. That will give you visibility into exactly what's happening with your object, what generation it is, what memory is being used by what and on and on. :)
如果您想深入了解正在发生的事情,请查看.NET Memory Profiler。这将使您能够准确地了解您的对象发生了什么,它是哪一代,什么正在使用什么内存等等。:)
回答by Savaratkar
Ok, I have a theory here... Dictionary is a collection of KeyValuePair which is again a reference type.
好的,我在这里有一个理论... Dictionary 是 KeyValuePair 的集合,它又是一个引用类型。
Your dictionary contains these keyValuePairs. When you say:
您的字典包含这些 keyValuePairs。当你说:
Txns = null
It frees the reference 'Txns' from those KeyValuePair collection. But still the actual memory of 150 Mb is being referenced by those KeyValuePair and they are in scope, thus not ready for garbage collection.
它从那些 KeyValuePair 集合中释放引用“Txns”。但是这些 KeyValuePair 仍然引用了 150 Mb 的实际内存,并且它们在范围内,因此还没有准备好进行垃圾收集。
But when you use the following:
但是当您使用以下内容时:
Txns.Clear();
Txns = null;
GC.Collect();
Here, the clear method also frees the 150Mb of data from their respective KeyValuePair object references. Thus those objects were ready for garbage collection.
这里,clear 方法还从它们各自的 KeyValuePair 对象引用中释放了 150Mb 的数据。因此,这些对象已准备好进行垃圾收集。
Its just a wild guess I am making here. Comments are welcome :)
这只是我在这里做的一个疯狂的猜测。欢迎评论:)