C# 在C语言中强制垃圾收集的最佳实践#
根据我的经验,似乎大多数人都会告诉你,强制垃圾收集是不明智的,但在某些情况下,如果你处理的大型对象在0代中并不总是被收集,但内存是一个问题,那么强制收集可以吗?有这样做的最佳实践吗?我学会了不要试图比垃圾收集更聪明。尽管如此,在处理非托管资源(如文件I/O或数据库连接)时,我还是坚持使用C# 在C语言中强制垃圾收集的最佳实践#,c#,.net,garbage-collection,C#,.net,Garbage Collection,根据我的经验,似乎大多数人都会告诉你,强制垃圾收集是不明智的,但在某些情况下,如果你处理的大型对象在0代中并不总是被收集,但内存是一个问题,那么强制收集可以吗?有这样做的最佳实践吗?我学会了不要试图比垃圾收集更聪明。尽管如此,在处理非托管资源(如文件I/O或数据库连接)时,我还是坚持使用关键字。不确定这是否是最佳做法,但在循环中处理大量图像时(即创建和处理大量图形/图像/位图对象),我定期让GC收集 我想我读到了GC只在程序(大部分)空闲的时候运行,而不是在一个密集循环的中间,所以它看起来像手动
关键字。不确定这是否是最佳做法,但在循环中处理大量图像时(即创建和处理大量图形/图像/位图对象),我定期让GC收集
<>我想我读到了GC只在程序(大部分)空闲的时候运行,而不是在一个密集循环的中间,所以它看起来像手动GC有意义的区域。 我想你已经列出了最好的实践,除非真正需要,否则不使用它。我强烈建议您更详细地查看代码,如果需要首先回答这些问题,可以使用分析工具
您的代码中是否有某些东西在比需要更大的范围内声明项
内存使用率真的太高了吗
比较使用GC.Collect()前后的性能,看看它是否真的有用
最好的做法是不要强制进行垃圾收集
根据MSDN:
“强制垃圾回收是可能的
通过调用Collect收集,但是
大多数情况下,这应该是
避免,因为它可能会造成
性能问题。”
但是,如果您能够可靠地测试代码,以确认调用Collect()不会产生负面影响,那么请继续
当你不再需要物品时,尽量确保物品被清理干净。如果您有自定义对象,请查看如何使用“using语句”和IDisposable接口
此链接提供了一些关于释放内存/垃圾收集等方面的实用建议:
大型对象在LOH(大型对象堆)上分配,而不是在gen 0上。如果你是说他们没有用gen 0收集垃圾,你是对的。我相信它们只有在整个GC循环(第0、1和2代)发生时才会被收集
也就是说,我相信在另一方面,当您处理大型对象时,GC会更积极地调整和收集内存,并且内存压力会增加
很难说是否收集以及在什么情况下收集。我曾经在处理带有许多控件的对话框窗口/窗体等之后执行GC.Collect()(因为当窗体及其控件最终进入gen 2时,由于创建了许多业务对象实例/加载了大量数据-显然没有大型对象),但实际上这样做并没有在长期内注意到任何积极或消极的影响。假设您的程序没有内存泄漏,对象会累积,并且无法在Gen 0中进行GC加密,因为:
1) 它们被引用了很长时间,因此进入Gen1和Gen2;
2) 它们是大对象(>80K),所以进入LOH(大对象堆)。LOH不像Gen0、Gen1和Gen2那样进行压缩
检查“.NET内存”的性能计数器,你会发现问题其实不是问题。通常,每10个Gen0 GC将触发1个Gen1 GC,每10个Gen1 GC将触发1个Gen2 GC。从理论上讲,如果GC0没有压力(如果程序内存使用真的是有线连接的话),GC1和GC2永远不会被GC-ed。我从来没有这样过
对于问题2),您可以检查“.NET内存”性能计数器以验证LOH是否膨胀。如果这确实是您的问题所在,也许您可以按照本博客的建议创建一个大型对象池。还有一件事,显式触发GC Collect可能不会提高程序的性能。很有可能使情况变得更糟
NET GC经过良好的设计和调整,具有自适应性,这意味着它可以根据程序内存使用的“习惯”调整GC0/1/2阈值。因此,它将在运行一段时间后适应您的程序。一旦显式调用GC.Collect,阈值将被重置!而.NET必须花时间再次适应您程序的“习惯”
我的建议是永远信任.NETGC。如果出现任何内存问题,请检查“.NET内存”性能计数器并诊断我自己的代码。这样看-当垃圾桶的容量为10%时,扔掉厨房垃圾是更有效的方法,还是让垃圾桶装满后再取出
如果不让垃圾填满,你就是在浪费时间,在外面的垃圾桶里走来走去。这类似于GC线程运行时发生的情况——所有托管线程在运行时都被挂起。如果我没有弄错的话,GC线程可以在多个AppDomain之间共享,因此垃圾收集会影响所有AppDomain
当然,你可能会遇到这样一种情况,即如果你打算去度假,你很快就不会往垃圾桶里添加任何东西。那么,出门前把垃圾扔掉是个好主意
这可能是强制GC有帮助的一次—如果您的程序空闲,则使用的内存不会被垃圾回收,因为没有分配
但是,如果您能够可靠地测试代码,以确认调用Collect()不会产生负面影响,那么请继续
IMHO,这类似于说“如果你能证明你的程序在将来永远不会有任何错误,那就继续吧…”
严格来说,强制GC对于调试/测试非常有用。如果您觉得需要在其他任何时候这样做,那么要么是您弄错了,要么是您的程序构建错误。无论哪种方式,解决方案都不会强制GC…我认为下面给出的示例很好:
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 = "";
}
}