Ech*_*orm 116 .net c# garbage-collection
根据我的经验,似乎大多数人会告诉你强制垃圾收集是不明智的,但在某些情况下,你正在使用大型对象,这些对象并不总是在0代收集,但内存是一个问题,是它可以强制收集?这样做有最好的做法吗?
Mar*_*ram 110
最佳做法是不强制进行垃圾回收.
根据MSDN:
"可以通过调用Collect来强制进行垃圾收集,但大多数情况下,这应该避免,因为它可能会产生性能问题."
但是,如果您可以可靠地测试代码以确认调用Collect()不会产生负面影响,那么请继续...
只是在不再需要时确保清理对象.如果您有自定义对象,请查看"using statement"和IDisposable接口.
这个链接在释放内存/垃圾收集等方面有一些很好的实用建议:
http://msdn.microsoft.com/en-us/library/66x5fx1b.aspx
Ian*_*ose 31
最佳做法是在大多数情况下不强制进行垃圾收集. (我所研究过的每个系统都强制进行垃圾收集,强调了如果解决问题就会消除强制垃圾收集的需要,并大大加快系统速度.)
在某些情况下,您可以了解有关内存使用情况的更多信息.在多用户应用程序或一次响应多个请求的服务中,这不可能成立.
但是在某些批处理类型处理中,您确实了解GC.例如,考虑一个应用程序.
您可能能够(经过仔细测试)测试后应该在处理完每个文件后强制执行完整的垃圾回收.
另一种情况是每隔几分钟醒来处理一些物品,并且在睡着时不保持任何状态的服务.然后在睡觉之前强制完整收集可能是值得的.
我唯一一次考虑强制收集的是当我知道最近创建了很多对象时,当前引用的对象非常少.
我宁愿有一个垃圾收集API,当我可以给它提示这种类型的东西,而不必强迫我自己的GC.
另见" Rico Mariani的表演花絮 "
Max*_*xam 30
看看这样的方式 - 是更有效的抛出了厨房垃圾时,垃圾可以在10%或服用之前让它填补?
不要让它填满,你浪费时间往外走垃圾桶.这类似于GC线程运行时发生的情况 - 所有托管线程在运行时都被挂起.如果我没有弄错,GC线程可以在多个AppDomain之间共享,因此垃圾收集会影响所有这些.
当然,你可能会遇到一种情况,你不会很快就会在垃圾桶里添加任何东西 - 比方说,如果你要休假.然后,在外出之前把垃圾丢掉是个好主意.
这可能是迫使GC可以提供帮助的一次 - 如果您的程序空闲,则使用的内存不会被垃圾收集,因为没有分配.
den*_*ips 21
我认为Rico Mariani给出的例子很好:如果应用程序的状态发生重大变化,可能适合触发GC.例如,在文档编辑器中,可以在文档关闭时触发GC.
小智 16
编程中很少有一般指导方针是绝对的.有一段时间,当有人说'你做错了'时,他们只是在喷出一定量的教条.在C语言中,过去常担心自修改代码或线程,在GC语言中它强制GC或者阻止GC运行.
与大多数指南和良好的经验法则(以及良好的设计实践)一样,在极少数情况下,围绕既定规范工作是有意义的.你必须非常确定你理解这个案子,你的案件确实需要废除普通的做法,并且你了解你可能导致的风险和副作用.但是有这样的情况.
编程问题种类繁多,需要灵活的方法.我已经看到了在垃圾收集语言中阻止GC以及触发它而不是等待它自然发生的地方的情况.95%的时间,其中任何一个都是没有正确处理问题的路标.但是在20年的一次,可能会有一个有效的案例.
Kon*_*Kon 12
我已经学会了不要试图超越垃圾收集.话虽如此,我只是using在处理非托管资源(如文件I/O或数据库连接)时坚持使用关键字.
不确定它是否是最佳实践,但是当在循环中处理大量图像时(即创建和处理大量图形/图像/位图对象),我经常让GC.Collect.
我想我在某处看到GC只在程序(大部分)空闲时运行,而不是在密集循环的中间运行,因此看起来像手动GC可能有意义的区域.
小智 9
我最近遇到的一个需要手动调用的情况GC.Collect()是处理大型C++对象,这些对象包含在很小的托管C++对象中,而这些对象又是从C#访问的.
垃圾收集器从未被调用,因为使用的托管内存量可以忽略不计,但是使用的非托管内存量非常大.手动调用Dispose()对象需要我跟踪自己何时不再需要对象,而调用GC.Collect()将清理任何不再被引用的对象.....
我认为你已经列出了最佳实践,除非真的需要,否则不要使用它.我强烈建议您更详细地查看您的代码,如果需要首先使用分析工具来回答这些问题.
假设您的程序没有内存泄漏,对象累积且无法在Gen 0中进行GC编辑,因为:1)它们被长时间引用,因此进入Gen1和Gen2; 2)它们是大型物体(> 80K),因此进入LOH(大物体堆).并且LOH不像Gen0,Gen1和Gen2那样进行压缩.
检查".NET内存"的性能计数器,你可以看到1)问题确实不是问题.通常,每10个Gen0 GC将触发1个Gen1 GC,每10个Gen1 GC将触发1个Gen2 GC.理论上,如果GC0没有压力(如果程序存储器使用情况确实有线),GC1和GC2永远不能进行GC编辑.它永远不会发生在我身上.
对于问题2),您可以检查".NET Memory"性能计数器以验证LOH是否变得臃肿.如果它确实是您的问题的问题,也许您可以创建一个大对象池,因为这篇博客建议http://blogs.msdn.com/yunjin/archive/2004/01/27/63642.aspx.
我想补充一点:调用 GC.Collect() (+ WaitForPendingFinalizers()) 是故事的一部分。正如其他人正确提到的,GC.COllect() 是非确定性收集,由 GC 本身 (CLR) 自行决定。即使您添加对 WaitForPendingFinalizers 的调用,它也可能不是确定性的。从此 msdn链接获取代码,并使用对象循环迭代为 1 或 2 运行代码。您将发现非确定性意味着什么(在对象的析构函数中设置断点)。准确地说,当只有 1 个(或 2 个)延迟对象时,不会调用析构函数 Wait..()。[引用要求]
如果您的代码正在处理非托管资源(例如:外部文件句柄),则必须实现析构函数(或终结器)。
这是一个有趣的例子:
注意:如果您已经尝试过 MSDN 中的上述示例,下面的代码将消除误会。
class Program
{
static void Main(string[] args)
{
SomePublisher publisher = new SomePublisher();
for (int i = 0; i < 10; i++)
{
SomeSubscriber subscriber = new SomeSubscriber(publisher);
subscriber = null;
}
GC.Collect();
GC.WaitForPendingFinalizers();
Console.WriteLine(SomeSubscriber.Count.ToString());
Console.ReadLine();
}
}
public class SomePublisher
{
public event EventHandler SomeEvent;
}
public class SomeSubscriber
{
public static int Count;
public SomeSubscriber(SomePublisher publisher)
{
publisher.SomeEvent += new EventHandler(publisher_SomeEvent);
}
~SomeSubscriber()
{
SomeSubscriber.Count++;
}
private void publisher_SomeEvent(object sender, EventArgs e)
{
// TODO: something
string stub = "";
}
}
Run Code Online (Sandbox Code Playgroud)
我建议,首先分析输出可能是什么,然后运行,然后阅读以下原因:
{析构函数仅在程序结束时隐式调用。为了确定性地清理对象,必须实现 IDisposable 并显式调用 Dispose()。这就是本质!:)
| 归档时间: |
|
| 查看次数: |
148389 次 |
| 最近记录: |