这有什么不对有关使用GC.Collect的()?

问题描述 投票:99回答:20

虽然我明白这个功能发挥的严重影响(或至少这是我认为),我不明白为什么它成为这些事情,可敬的程序员,就永远使用一种,即使是那些谁也不知道它是什么。

比方说,我正在开发内存使用量变化极其这取决于用户正在做一个应用程序。应用程序生命周期可以分为两个主要阶段:编辑和实时处理。在编辑阶段,假设数十亿,甚至创建对象的万亿;他们中的一些小的,其中有些不是,有些人可能有终结,有些可能不是,并假设他们的一生,从一个非常几毫秒到长时间的变化。接下来,用户决定切换到实时阶段。在这一点上,假设性能起着至关重要的作用,并在程序的流程丝毫改变可能带来灾难性的后果。然后创建对象是通过使用对象池和等,但随后降低到最低可能,GC编钟意外并抛出了这一切,有人死亡。

问题:在这种情况下,它不会是明智的进入第二阶段之前调用GC.Collect()?

毕竟,这两个阶段从未在时间上彼此,所有的优化和统计GC可能已经聚集用处不大这里重叠...

注:由于你们有些人指出,.NET可能不适合这样的应用程序的最佳平台,但这已经超出了这个问题的范围。这样做的目的是澄清GC.Collect的()调用是否可以提高应用程序的整体行为/性能与否。我们都同意下,你会做这样的事情的情况是非常罕见的,但话又说回来,在GC试图猜测,并且做得非常非常清楚的大部分时间,但它仍然是关于猜测。

谢谢。

.net performance memory-management garbage-collection
20个回答
87
投票

From Rico's Blog...

规则1

别。

这真的是最重要的规则。公平地说,所以GC.Collect()的大多数应用是一个坏主意,我走进的是,在原单张贴一些细节,所以我不会重复所有在这里。因此,让我们继续...

规则#2

考虑调用GC.Collect的(),如果一些非经常性事件刚刚发生,这一事件极有可能已经造成了很多旧物死亡。

这方面的一个典型的例子是,如果你正在写一个客户端应用程序和你显示,有很多与之相关的数据的一个非常大的和复杂的形式。您的使用者互动这种形式可能会创建一些大型物体...事情如XML文件,或大型数据集或两个。当窗体关闭这些对象是死的,因此所以GC.Collect()将回收与之相关的记忆...

所以,它听起来像这种情况可能属于按照规则#2,你知道,有时间上的时刻,很多老的对象已经死亡,它的非经常性损益。但是,不要忘了波多黎各的临别赠言。

规则#1应该王牌规则#2无强有力的证据。

测量,测量,测量。


6
投票

在一个循环中创建的图像 - 即使你打电话配置,内存不恢复。垃圾收集每一次。我从1.7GB内存继续我的照片处理应用到24MB,性能非常出色。

有绝对的时间,你需要调用GC.Collect。


6
投票

逸岸,我不认为这是一个非常不好的做法,调用GC.Collect。 可能有情况下,当我们需要。只是举例来说,我有一个运行的线程,这inturn打开不同的充数据库中的表形式,提取的BLOB字段的内容到一个临时文件,加密的文件,那么文件读入到一个binarystream并返回到BLOB现场另一个表。

整个操作需要相当大量的内存,这是不能确定的行表中的数量和文件内容大小。 我以前经常得到OutOfMemory例外,我认为这将是明智的基于计数器变量定期运行GC.Collect的。我增加一个计数器,并达到规定的水平时,GC被称为收集可能形成的任何垃圾,回收由于不可预见的内存泄漏失去了任何的记忆。

在此之后,我认为这是很好的工作,至少也不例外! 我拨打以下方式:

var obj = /* object utilizing the memory, in my case Form itself */
GC.Collect(GC.GetGeneration(obj ,GCCollectionMode.Optimized).

5
投票

.NET下,执行垃圾收集所需的时间更密切相关的,是不是垃圾,而不是是东西量的东西的量。事实上,除非一个对象覆盖Finalize(显式或经由C#析构函数),是一种WeakReference的目标时,坐在大对象堆,或者是特殊的其他一些GC-相关方式,确定所述存储器中的唯一的东西,其中它位于作为一个目的是它根引用的存在。否则,GC的操作类似于从价值的建筑采取的一切,和使用炸药的建筑,建筑旧的网站上一个新的,并把所有的贵重物品在里面。要炸毁大楼所需要的努力是完全独立的在它的垃圾量。

因此,呼吁GC.Collect容易提高工作系统必须做的总量。它会延迟下收集的发生,但可能会做立即,因为它发生时的下一集将需要一样多的工作;在当下的收集会发生点,时间总量花在收集将一直大约相同的有GC.Collect没有被调用,但系统会积累了一些垃圾,造成随后的集合可以被更快地需要比有GC.Collect没有被调用。

我可以看到GC.Collect真的是有用的时间是指当一个人需要任何措施的一些代码的内存使用(因为内存使用数字只是实际意义,下面的集合),或轮廓哪几种算法是更好的(调用GC.Collect的( )前运行的每个数块的代码可以帮助确保一致的基准状态)。还有一些其他的情况下,一个可能知道事情的GC没有,但除非是写一个单线程程序,有没有办法可以知道,GC.Collect通话,这将有助于一个线程的数据结构,避免“中年危机”不会导致其他线程的数据有一个‘否则将被避免中年危机’。


4
投票

我们与垃圾收集器收集没有垃圾和释放内存类似的问题。

在我们的程序,我们正在处理一些适度大小的Excel电子表格与OpenXML的。电子表格从5至10“片材”的任何位置包含约1000行14列。

在一个32位的环境(86)中的程序将与“内存”的错误崩溃。我们没有得到它在64位环境中运行,但我们需要一个更好的解决方案。

我们找到了一个。

下面是一些简单的代码片断什么没有工作的,什么是工作,当谈到显式调用垃圾收集器已批出对象释放内存。

从调用里面的子程序没有工作的GC。记忆从未被开垦...

For Each Sheet in Spreadsheets
    ProcessSheet(FileName,sheet)
Next

Private Sub ProcessSheet(ByVal Filename as string, ByVal Sheet as string)
    ' open the spreadsheet 
    Using SLDoc as SLDocument = New SLDocument(Filename, Sheet)
        ' do some work....
        SLDoc.Save
    End Using
    GC.Collect()
    GC.WaitForPendingFinalizers()
    GC.Collect()
    GC.WaitForPendingFinalizers()
End Sub

通过移动GC调用子程序的范围之外,垃圾收集,并且将内存被释放。

For Each Sheet in Spreadsheets
    ProcessSheet(FileName,sheet)
    GC.Collect()
    GC.WaitForPendingFinalizers()
    GC.Collect()
    GC.WaitForPendingFinalizers()
Next

Private Sub ProcessSheet(ByVal Filename as string, ByVal Sheet as string)
    ' open the spreadsheet 
    Using SLDoc as SLDocument = New SLDocument(Filename, Sheet)
        ' do some work....
        SLDoc.Save
    End Using
End Sub

我希望这可以帮助其他人感到沮丧与.NET垃圾收集时,它似乎忽略调用GC.Collect()

保罗·史密斯


4
投票

没有什么是错明确要求的集合。有些人只是真的要相信,如果它是由供应商提供的服务,不要怀疑它。哦,一切尽在您的交互式应用的错误时刻的随机结冰?下一个版本将做的更好!

让一个后台进程处理存储器操作意味着不必处理它自己,真的。但是,这并不意味着在逻辑上,这是对我们最好不要用它自己在所有情况下处理。在GC是在大多数情况下进行了优化。但是,这并不意味着在逻辑上,它是在所有情况下进行了优化。

你有没有回答一个悬而未决的问题,如“这是最好的排序算法”有一个明确的答案?如果是这样,不要触摸GC。对于那些你们谁“在这种情况下,”类型的答案问的条件,还是给了,你可以继续了解GC以及何时激活它。

不得不说,我已经在Chrome和Firefox的应用程序冻结是阻挠了我的地狱,甚至然后某些情况下,内存的增长不受阻碍 - 如果他们想学习调用垃圾收集器 - 或者给我一个按钮,这样当我开始阅读页面的文本,我可以打它,从而为接下来的20分钟是免费的冻结的。


2
投票

我认为你是对有关场景,但我不知道的API。

微软表示,在这种情况下,你应该add memory pressure以提示,它应该很快进行收集GC。


2
投票

它出什么问题了?那你的猜测垃圾收集和内存分配器,这两者之间有关于你的应用程序的实际内存使用量更大的想法在运行时比你做的事实。


2
投票

的愿望,调用GC.Collect()通常是试图掩盖为你做别的地方出错!

如果你发现,你忘了处置的东西,你也不再需要这将是更好的。


1
投票

底线是,你可以分析应用程序,看看这些额外的集合是如何影响的事情。我建议住远离它,但除非你要的资料。该GC的目的是自己照顾自己和运行时的发展,他们可能会提高效率。你不想挂在可能弄脏的作品,而不是能够利用这些改进一串代码。若您使用的foreach而不是为,那是,那在幕后未来的改进可以被添加到的foreach和你的代码没有改变,以利用一个类似的说法。


1
投票

.NET框架本身从来不是用于在实时环境中运行。如果你真的需要实时处理,你要么使用不基于.NET的嵌入式实时语言或使用Windows CE设备上运行.NET Compact Framework的。


56
投票

如果您在生产代码中调用GC.Collect()你基本上声明,你知道那么多的GC的作者。这可能是这种情况。但是它通常不是,因此强烈反对。


1
投票

它会做的最糟糕的就是让你的程序冻结了一下。所以,如果这是你OK,做到这一点。通常它不需要与大部分用户交互胖客户端或Web应用程序。

我发现,有时会长时间运行的线程,或批处理程序,程序将获得OutOfMemory例外,即使他们正确处理对象。其中我记得是一个业务线的数据库事务处理;另一个是在厚客户端应用程序在后台线程的指数例行程序。

在这两种情况下,结果很简单:没有GC.Collect的,内存,始终如一; GC.Collect的,完美的表现。

我试着用它来解决内存问题的其他几次,也没有用。我把它。

总之,不要把它,除非你得到的错误。如果你把它和它没有解决内存问题,把它退了出去。请记住,在释放模式来测试和比较苹果和苹果。

唯一的一次,事情都可能出错,这是当你说教了。这不是一个问题的值;许多程序员都死了,直接去了天堂,在自己的代码,这会超越他们很多不必要GC.Collects。


23
投票

因此,如何当你使用的是像MS Word或MS Excel的COM对象从.NET?不释放COM对象后调用GC.Collect我们发现,Word或Excel应用程序实例仍然存在。

事实上,我们使用的代码是:

Utils.ReleaseCOMObject(objExcel)

' Call the Garbage Collector twice. The GC needs to be called twice in order to get the
' Finalizers called - the first time in, it simply makes a list of what is to be finalized,
' the second time in, it actually does the finalizing. Only then will the object do its 
' automatic ReleaseComObject. Note: Calling the GC is a time-consuming process, 
' but one that may be necessary when automating Excel because it is the only way to 
' release all the Excel COM objects referenced indirectly.
' Ref: http://www.informit.com/articles/article.aspx?p=1346865&seqNum=5
' Ref: http://support.microsoft.com/default.aspx?scid=KB;EN-US;q317109
GC.Collect()
GC.WaitForPendingFinalizers()
GC.Collect()
GC.WaitForPendingFinalizers()

所以,那会是一个不正确的使用垃圾收集的?如果是这样,我们如何互操作的对象死吗?此外,如果并不意味着它像这样被使用,为什么是GCCollect方法甚至Public


15
投票

那么,GC是这些东西我有一个爱/恨的关系之一。我们有broken it in the past通过VistaDB的和博客上讲述它。他们有固定的,但它需要很长时间才能从他们身上得到这样的事情修复。

在GC是复杂的,一个一刀切的做法是非常,非常努力拉断的东西这么大。 MS做它的一个相当不错的工作,但它有可能愚弄有时在GC。

一般来说,你不应该添加一个Collect,除非你知道你只是把一吨的内存事实,它会去mid life crisis如果GC没有得到它现在清理。

您可以搞砸了整个机器的一系列坏GC.Collect语句。需要付费的声明几乎总是指向一个更大的潜在错误。内存泄漏通常与参考和他们是如何工作缺乏了解的事情。或者在不需要它的对象IDisposable的使用,并把在GC更高的负载。

仔细观察,通过该系统性能计数器在GC上花费的时间的百分比。如果你看到使用20%或更多的时间您的应用程序在GC你有严重的对象管理问题(或不正常使用模式)。你要总是尽量减少GC花费,因为它会加快您的整个应用程序的时间。

同样重要的是要注意,GC是比工作站服务器不同。我已经看到了一些小很难跟踪与人没有测试他们两人的问题(甚至不知道他们是两个)。

而只是在我的答案尽可能完整的,你也应该在Mono下测试,如果你的目标是平台也是如此。因为它是一个完全不同的实现中,它可能会出现完全不同的问题,即MS执行。


13
投票

在有些情况下是非常有用的情况,但一般应该避免。你可以把它比作GOTO,或骑助力车:你这样做的时候,你需要的,但你不要告诉你的朋友。


12
投票

从我的经验,从来没有建议使生产代码,所以GC.Collect()的调用。在调试,是的,它有它的优势,帮助澄清潜在的内存泄漏。我想我的根本原因是,GC已经书面和程序员要聪明得多优化那时的我,如果我到一个地步,我觉得我需要调用GC.Collect()这是一个线索,我已经关闭路径某处。在你的情况这听起来并不像你确实有内存问题,只是你所关心的收集将带给你什么样的过程不稳定。眼看着它在使用中不会还在清理的对象,而且它适应得很快双方的需求上升和下降,我想你将不必担心。


10
投票

其中一个最大的原因,调用GC.Collect()是当你刚刚完成其产生大量的垃圾,比如你描述一个显著的事件。所以GC.Collect调用()都可以在这里是个好主意;否则,GC可能不明白,这是一个“一次性”的事件。

当然,你就应该剖析它,并看到自己。


9
投票

显然,你不应该写在语言的实时性要求与非实时垃圾收集代码。

在具有良好定义的阶段的情况下,存在与触发垃圾收集器没有问题。但这种情况是极为罕见的。问题是,许多开发商正打算尝试用它来在货物邪教式的纸张上的问题,并增加它不加区别地将导致性能问题。


7
投票

所以GC.Collect调用()强制CLR做堆栈行走,看看每个对象可以忠实地被检查参考释放。这将影响到可扩展性,如果对象的数量高,也被称为引发垃圾收集太频繁。相信CLR和让垃圾收集器运行本身在适当的时候。

© www.soinside.com 2019 - 2024. All rights reserved.