当前位置: 首页 > 编程语言 > C#

使用GC.Collect();是否正确?GC.WaitForPendingFinalizers();-分享

时间:2023-04-10 16:04:35 C#

GC.Collect();GC.WaitForPendingFinalizers();的使用正确吗?我已经开始查看项目中的一些代码并发现类似这样的内容:GC.Collect();GC.WaitForPendingFinalizers();这些线通常出现在理论上应该以效率为基础销毁物体的方法上。我做了这样的声明:在每个对象的销毁时显式调用垃圾收集会损害性能,因为如果它对CLR性能绝对必要,则不会考虑。按此顺序调用这些指令会导致每个对象仅在其他对象完成时才被销毁。因此,一个可以独立销毁的对象必须等待其他对象的销毁,而不是必要的。它会产生死锁(参见:这个问题)1、2和3都是真的吗?您能否提供一些支持您的答案的参考资料?虽然我几乎可以肯定自己的话,但我需要清楚地说明我的论点,以便向我的团队解释为什么这是一个问题。这就是为什么我要求确认和参考。简短的回答是:把它拿出来。该代码几乎永远不会提高性能或长期内存使用。你所有的观点都是正确的。(它会产生死锁;这并不意味着它总是会。)调用GC.Collect()将收集所有GC生成的内存。这有两件事。如果没有GC.Collect(),这两个项目将在下一次机会时被收集。在写入集合时,o2将在Gen1中结束——这意味着自动Gen0集合不会释放该内存。还有一个可怕的地方值得注意:在DEBUG模式下,GC的功能不同并且不会回收仍在范围内的任何变量(即使它没有在当前方法中使用)。所以在DEBUG模式下,上面的代码在调用GC.Collect时甚至不会收集o1,所以o1和o2都会被引发。在调试代码时,这可能会导致一些非常不稳定和意外的内存使用。(像这样的文章强调了这种行为。)编辑:刚刚测试了这种行为,有些讽刺:如果你有这样的方法:voidCleanUp(ThingsomeObject){someObject.TidyUp();一些对象=空;GC.收集();GC.WaitForPendingFinalizers();}...然后它将显式释放someObject的内存,即使在RELEASE模式下:它会将其提升到下一代GC生成。有一点很好理解:GC操作每次运行都会自动清理多个对象(比如10000个)。在每次销毁后调用它会一次清理一个对象。因为GC的开销很高(需要停止和启动线程,需要扫描所有对象的活动),所以非常需要批处理调用。另外,每个对象在清理后有什么用?这怎么可能比批处理更有效?您的第3点在技术上是正确的,但只有在有人在最终确定期间锁定时才会发生。即使没有那个调用,在终结器中锁定也比这里的情况更糟糕。有一些对GC.Collect()的调用确实有助于提高性能。到目前为止,我在我的职业生涯中做过2次,也许3次。(或者,如果你包括我所做的那些,可能大约5或6次,测量结果,然后再次取出-你应该经常做的事情)。如果您在短时间内使用数百或GB的内存,然后在很长一段时间内切换到不太密集的内存使用,显式收集可能是一个巨大甚至重要的改进。这是怎么回事?在其他任何地方,它们最多会使速度变慢并使用更多内存。在这里查看我的其他答案:ToGC.Collectornot?当您自己调用GC.Collect()时会发生两件事:您最终会花费更多时间进行收集(因为除了手动GC.Collect()之外还会发生正常的后台收集)并且您会坚持更长时间的记忆(因为你强迫某些东西进入更高阶的生成而不需要去那里)。换句话说,自己使用GC.Collect()几乎总是一个坏主意。大约唯一一次您想要自己调用GC.Collect()是当您有关于您的程序的特定信息时,垃圾收集器很难知道。典型示例是一个长时间运行的程序,具有明显的繁忙和轻周期。您可能希望在繁忙期之前的轻负载期结束时强制进行收集,以确保资源在繁忙期尽可能空闲。但即使在这里,您可能会发现通过重新思考您的应用程序的构建方式您可以做得更好(即计划任务工作得更好吗?)。我只用过一次:清除CrystalReport文档的服务器端缓存。查看CrystalReportsException中的响应:已达到系统管理员配置的最大报表处理作业限制WaitForPendingFinalizers对我特别有帮助,因为有时对象没有正确清理。考虑到网页中报告的相对较慢的性能-任何微小的GC延迟都可以忽略不计,内存管理方面的改进使我的服务器总体上更快乐。我们遇到了与@Grzenio类似的问题,但我们使用的是更大的二维数组,大约1000x1000到3000x3000,这是在Web服务中。添加更多内存并不总是正确的答案,您必须了解您的代码和用例。如果没有GC,我们需要16-32GB的内存(取决于客户端的大小)。如果没有它,我们将需要32-64GB的RAM,即使那样也不能保证系统不会受到影响。.NET垃圾收集器并不完美。我们的web服务有一个内存缓存,大小为50-500k字符串(每个键/值对大约80-140个字符,取决于配置),每个客户端请求我们将在2个矩阵之间构造一个,其中一个然后将布尔值传递给另一个服务来完成工作。对于1000x1000“矩阵”(二维数组),每个请求大约25mb。布尔值会说明我们需要哪些元素(基于我们的缓存)。每个缓存条目代表“矩阵”中的一个“单元格”。当服务器由于分页而具有>80%的内存利用率时,缓存性能会急剧下降。我们发现,除非我们明确地进行GC,否则.net垃圾收集器永远不会“清理”临时变量,直到我们处于90-95%的范围内,此时缓存性能已大大降低。由于下游过程通常需要很长时间(3-900秒),因此GC收集的性能损失可以忽略不计(每次收集3-10秒)。在将响应返回给客户端后,我们开始收集。最后我们使GC参数可配置,.net4.6也有其他选项。这是我们使用的.net4.5代码。如果(sinceLastGC.Minutes>Service.g_GCMinutes){Service.g_LastGCTime=DateTime.Now;varsw=Stopwatch.StartNew();longmemBefore=System.GC.GetTotalMemory(false);context.Response.Flush();语境。ApplicationInstance.CompleteRequest();System.GC.Collect(Service.g_GCGeneration,Service.g_GCForced?System.GCCollectionMode.Forced:System.GCCollectionMode.Optimized);System.GC.WaitForPendingFinalizers();longmemAfter=System.GC.GetTotalMemory(true);varelapsed=sw.ElapsedMilliseconds;Log.Info(string.Format("GC以{0}字节开始,以{1}字节结束,GC时间{2}(ms)",memBefore,memAfter,elapsed));重写后使用.NET4.6,我们将垃圾收集器分为两个步骤-简单收集和压缩收集。publicstaticRunGC(GCParametersparam=null){lock(GCLock){vartheParams=param??GC参数;varsw=Stopwatch.StartNew();vartimestamp=DateTime.Now;longmemBefore=GC.GetTotalMemory(false);GC.Collect(theParams.Generation,theParams.Mode,theParams.Blocking,theParams.Compacting);GC.WaitForPendingFinalizers();//GC.收集();//可能需要收集终结器创建的死对象varelapsed=sw.ElapsedMilliseconds;longmemAfter=GC.GetTotalMemory(true);Log.Info($"GC以{memBefore}字节开始,以{memAfter}字节结束,GC时间{elapsed}(ms)");}}//https://msdn.microsoft.com/en-us/library/system.runtime.gcsettings.largeobjectheapcompactionmode.aspxpublicstaticRunCompactingGC(){lock(CompactingGCLock){varsw=Stopwatch.StartNew();vartimestamp=DateTime.Now;longmemBefore=GC.GetTotalMemory(false);GCSettings.LargeObjectHeapCompactionMode=GCLargeObjectHeapCompactionMode.CompactOnce;GC.收集();varelapsed=sw.ElapsedMilliseconds;longmemAfter=GC.GetTotalMemory(true);Log.Info($"CompactingGC以{memBefore}字节开始,以{memAfter}字节结束,GC时间{elapsed}(ms)");希望这对某人有所帮助,因为我们花了很多时间研究上面的C#学习教程:IsitcorrecttouseGC.Collect();GC.WaitForPendingFinalizers();?如果所有分享的内容对你有用,需要进一步了解C#学习教程,希望大家多多关注。本文收集自网络,不代表立场。如涉及侵权,请点击右侧联系管理员删除。如需转载请注明出处: