【问题标题】:Garbage Collection on one object, C#一个对象上的垃圾收集,C#
【发布时间】:2009-03-13 20:40:48
【问题描述】:

我需要处理一个对象,以便它可以释放它拥有的所有东西,但它没有实现 IDisposable,所以我不能在 using 块中使用它。我怎样才能让垃圾收集器收集它?

【问题讨论】:

    标签: c# .net-3.5 garbage-collection


    【解决方案1】:

    您可以使用 GC.Collect() 强制收集。使用它时要非常小心,因为完整的集合可能需要一些时间。最佳实践是让 GC 确定最佳收集时间。

    对象是否包含非托管资源但未实现 IDisposable?如果是这样,那就是一个错误。

    如果没有,它是否被立即释放也没关系,垃圾收集器应该做正确的事情。

    【讨论】:

    • 我认为他的问题是因为它包含托管资源,但它使用了很多资源,所以他希望在不再需要对象时立即释放它们。
    • 如果是这种情况,让GC处理它。如果资源足够大并施加足够的内存压力,它将在下一代 0 GC 时处理。
    • 实际上,它拥有一个套接字,我希望尽快释放该套接字,但我无法自己关闭该套接字。
    • @Malfist:那么您需要更改对象,即使这意味着更改供应商。
    • 你能调用 Socket.Close() 吗?这将释放套接字的资源。
    【解决方案2】:

    如果它“拥有”内存以外的任何东西,则需要修复对象以使用 IDisposable。如果它不是您控制的对象,则值得选择不同的供应商,因为它说明了您的供应商对 .Net 的理解程度的核心。

    如果它只是拥有内存,即使是很多内存,你所要做的就是确保对象超出范围。 不要打电话给GC.Collect()——这是如果你不得不问的事情之一,你不应该这样做。

    【讨论】:

    • 对象来自库,我无法控制它。它拥有一个套接字,我需要关闭并重新创建该套接字,但是当它持有它并且我无法访问该套接字时我无法执行此操作。
    • 解决方案 #1,这是您的快速解决方案:调用 GC.Collect();解决方案 #2,这是长期(且正确)的解决方法:放弃该库并获得一个新库。
    • #2 并不总是一个选项 :)
    【解决方案3】:

    您不能对单个对象执行垃圾回收。您可以通过调用 GC.Collect() 来请求垃圾回收,但这会影响所有需要清理的对象。也非常不鼓励这样做,因为它可能会对以后收集的性能产生负面影响。

    此外,对对象调用 Dispose 不会清理它的内存。它只允许对象删除对非托管资源的引用。例如,在 StreamWriter 上调用 Dispose 会关闭流并释放 Windows 文件句柄。托管堆上的对象的内存在后续垃圾回收之前不会被回收。

    Chris Sells 也在 .NET Rocks 上讨论过这个问题。我想那是他第一次露面的时候,但后来的采访中可能会重新讨论这个话题。

    http://www.dotnetrocks.com/default.aspx?showNum=10

    Francesco Balena 的这篇文章也是一个很好的参考:

    何时以及如何在 C# 中使用 Dispose 和 Finalize http://www.devx.com/dotnet/Article/33167/0/page/1

    【讨论】:

      【解决方案4】:

      如果对象超出范围并且它没有外部引用,它将很快被收集(可能在下一次收集时)。

      【讨论】:

      • 不一定。例如。如果它已经移至第 2 代,则可能需要一段时间,如果有一个未决的终结器,则需要两次收集。
      【解决方案5】:

      .NET 中的垃圾收集是不确定的,这意味着您无法真正控制它何时发生。你可以建议,但这并不意味着它会听。

      告诉我们更多关于该对象的信息以及您为什么要这样做。我们可以据此提出一些建议。代码总是有帮助的。根据对象的不同,可能会有 Close 方法或类似的方法。也许用途就是这样称呼。如果没有 Close 或 Dispose 类型的方法,您可能不想依赖该对象,因为如果实际上它确实包含需要释放的资源,您可能会遇到内存泄漏。

      【讨论】:

        【解决方案6】:

        注意:在许多情况下,GC.Collect() 或一些IDisposal片段 > 不是很有帮助,尤其是对于大型对象(LOH 适用于 ~80kb+ 的对象,执行不压缩和对于许多常见用例而言,会受到高度的碎片化),这将导致内存不足 (OOM) 问题,即使可能有数百个 MB免费。随着时间的推移,事情变得越来越大,虽然对于 LOH 降级对象来说可能不是这个大小(80 kb),但高度的并行性加剧了这个问题,这仅仅是因为在更短的时间内有更多的对象(并且可能大小不同)被实例化/发布。

        数组是这个问题的常见嫌疑人(它也经常由于非特定异常和运行时的断言而难以识别,类似“高百分比的大对象堆碎片”会膨胀),遇到此问题的代码的预后实施积极的重用策略。

        parallel extensions beta1 samples 中的 Systems.Collections.Concurrent.ObjectPool 中的一个类有帮助(不幸的是,我没有看到一个简单的普遍存在的模式,比如一些附加的属性/扩展方法?) ,对于大多数项目来说,插入或重新实现非常简单,您分配一个生成器 Func 并使用 Get/Put 辅助方法来重用您以前的对象并放弃通常的垃圾收集。 关注数组而不是单个数组元素通常就足够了。

        如果 .NET 4 更新所有 .ToArray() 方法以包含 .ToArray(T 目标),那就太好了。

        掌握使用 SOS/windbg (.loadby sos mscoreei for CLRv4) 来分析此类问题会有所帮助。想一想,现在的垃圾回收系统更像是垃圾回收(再次使用相同的物理内存),ObjectPool 类似于垃圾回收。如果有人记得 3R,那么出于性能考虑,减少内存使用也是一个好主意;)

        【讨论】:

          猜你喜欢
          • 2011-07-16
          • 1970-01-01
          • 2010-11-08
          • 1970-01-01
          • 2012-01-28
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多