C# - 在调用GC.Collect之前为GC准备对象

时间:2010-11-10 11:18:36

标签: c# garbage-collection

方案

  • 假设我已经决定我真的需要调用GC.Collect();
  • 在实际调用此方法之前,我需要做些什么来确保对象准备好进行适当的垃圾回收?
  • 将null赋给对象的所有属性是否足够?或者只是将null赋给对象本身?

如果你真的需要知道为什么......

  • 我在WCF中有一个分布式应用程序,它每隔几秒就通过网络发送一个DataContract,其中包含8个Dictionaries作为DataMembers。
  • 这是很多数据,当它进入客户端接口时,会创建一个全新的DataContract对象,并且应用程序的内存使用量正在增长,以至于我得到了OutOfMemory Exceptions。

由于

修改

感谢所有的评论和回答,似乎每个人都持有同样的观点。

  • 我无法理解的是我如何正确处理,因为连接是不断打开的。
  • 一旦我从传入的对象复制了数据,我就不再需要该对象,那么只需在该DataContract对象上实现IDisposable即可吗?
  • 我原来的问题在这里 - Distributed OutOfMemory Exceptions

6 个答案:

答案 0 :(得分:3)

只要没有其他任何东西可以看到对象,它就已经有资格收集;没有必要。这里的关键是确保没有其他东西正在观看它(或者至少没有其他东西在观看它):

  • 它在某个地方吗?
  • 是一个不完整的方法中的变量吗? (也许是一个无限循环或迭代器块)
  • 是否在某个地方收藏?
  • 订阅了一些活动吗?
  • 它是在一个仍然存活的闭包(lambda / anon-method)中捕获的?

我真的怀疑GC.Collect()是这里的答案;如果它符合条件,它就已经被收集了。如果不是可以识别,那么调用GC.Collect()肯定无济于事,很可能会使事情变得更糟(通过在没有任何有用的东西时收集CPU)。

答案 1 :(得分:2)

您通常不需要做任何事情。

如果不再引用该对象,则它是收集的候选对象。 (相反,如果对象仍被引用,则它不是收集的候选者,但是你“准备”它。)

答案 2 :(得分:1)

您需要清理任何非托管资源,如数据库连接等。
通常是通过实施IDisposable并致电Dispose

如果您有终结器,请拨打GC.SuppressFinilize

其余部分由垃圾收集器清理。

修改
而且,哦,当然你需要释放对象的所有引用。

但是,这是一个很大但是。除非你有一个非常特殊的情况,否则你不需要调用GC.Collect。您可能忘记释放一些资源或引用,GC.Collect将无法帮助您。确保在所有Disposable上调用Dispose(最好使用使用模式)。

你应该选择一个像Ants memory profiler这样的内存分析器,看看你的所有内存消失了。

答案 3 :(得分:1)

如果您没有对某个对象的更直接引用,并且内存不足,GC应该自动执行此操作。确保在datacontext上调用.Dispose()。

答案 4 :(得分:1)

调用GC.Collect几乎不会阻止您获取OutOfMemory异常,因为当由于OOM而无法创建新对象时,.NET将调用GC.Collect。我只能想到一个场景,那就是当你有可以在可终结队列中注册的未引用对象时。当这些对象引用许多其他对象时,它可能会导致OOM。这个问题的解决方案实际上不是调用GC.Collect,而是确保正确放置这些对象(并在创建这些对象时正确实现dispose模式)。

答案 5 :(得分:1)

一般使用GC.Collect

因为你试图摆脱一个非常大的集合,所以使用GC.Collect()是完全有效的。来自Microsoft docs

  

...因为您的应用程序比运行时更了解其行为,所以您可以通过显式强制某些集合来帮助解决问题。例如,您的应用程序在用户保存其数据文件后强制完整收集所有代数可能是有意义的。

“准备”您的对象

来自优秀的Performance Considerations for Run-Time Technologies in the .NET Framework(来自MSDN):

  

如果您保留指向资源的指针,GC无法知道您是否打算将来使用它。这意味着您在本机代码中用于显式释放对象的所有规则仍然适用,但大多数情况下GC将为您处理所有内容。

因此,为了确保它已准备好用于GC,请确保您没有对要收集的对象的引用(例如,在集合,事件等中)。将变量设置为null意味着在变量超出范围之前它已准备好进行收集。

任何实现IDisposable的对象都应该调用它的Dispose()方法来清理非托管资源。

使用GC.Collect之前

由于您的应用程序看起来像是服务器,因此使用Server GC可能会解决您的问题。在多处理器场景中,它可能会更频繁地运行并且性能更高。

  

服务器GC旨在实现最大吞吐量,并以非常高的性能进行扩展。

Performance Considerations for Run-Time Technologies in the .NET Framework(来自MSDN)中查看选择要使用的垃圾收集器