简体   繁体   English

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

[英]C# - Preparing An Object For GC Before Calling GC.Collect

Scenario 情境

  • Lets say that I've decided I really need to call GC.Collect(); 可以说,我已经决定确实需要调用GC.Collect();。
  • What do I need to do to ensure that an object is prepared to be garbage collected appropriately before I actually call this method? 在实际调用此方法之前,我需要做些什么来确保准备好适当地垃圾回收对象?
  • Would assigning null to all properties of the object be enough? 将null分配给对象的所有属性是否足够? Or just assigning null to the object itself? 还是只为对象本身分配null?

If you really need to know why..... 如果您真的需要知道为什么.....

  • I have a distributed application in WCF that sends a DataContract over the wire every few seconds, containing 8 Dictionaries as DataMembers. 我在WCF中有一个分布式应用程序,该应用程序每隔几秒钟通过电线发送一个DataContract,其中包含8个字典作为DataMembers。
  • This is a lot of data and when it comes into the Client-side interface, a whole new DataContract object is created and the memory usage of the application is growing so big that I'm getting OutOfMemory Exceptions. 这是大量数据,当它进入客户端接口时,会创建一个全新的DataContract对象,并且应用程序的内存使用量正在增长,以至于我收到OutOfMemory Exceptions。

Thanks 谢谢

EDIT 编辑

Thanks for all the comments and answers, it seems that everyone shares the same opinion. 感谢您的所有评论和回答,似乎每个人都有相同的看法。

  • What I cannot understand is how I can possibly dispose correctly because the connection is open constantly. 我不明白的是,由于连接一直处于打开状态,我如何正确处理。
  • Once I've copied the data over from the incoming object, I don't need the object anymore, so would simply implementing IDisposable on that DataContract object be enough? 一旦从传入对象复制了数据,就不再需要该对象,那么仅在该DataContract对象上实现IDisposable就足够了吗?
  • My original problem is here - Distributed OutOfMemory Exceptions 我的原始问题在这里- 分布式OutOfMemory异常

As long as nothing else can see the object it is already eligible for collection; 只要没有其他东西可以看到该对象 ,则该对象已经可以收集。 nothing more is required. 不再需要。 The key point here is to ensure that nothing else is watching it (or at least, nothing with a longer lifetime): 这里的关键点是确保没有其他人在看它(或者至少没有任何人有更长的寿命):

  • is it in a field somewhere? 在某个地方的田野里吗?
  • is it in a variable in a method that is incomplete? 是在不完整的方法中的变量中吗? (an infinite loop or iterator block, perhaps) (也许是无限循环或迭代器块)
  • is it in a collection somewhere? 在某个地方的收藏中吗?
  • has it subscribed to some event? 它订阅了某个活动吗?
  • it is captured in a closure (lambda / anon-method) that is still alive? 它被捕获在一个还活着的闭包(lambda /匿名方法)中?

I genuinely doubt that GC.Collect() is the answer here; 我真的怀疑GC.Collect()是这里的答案。 if it was eligible it would have already been collected. 如果符合条件,它将已经被收集。 If it isn't elgible, calling GC.Collect() certainly won't help and quite possibly will make things worse (by tying up CPU when nothing useful can be collected). 如果不是 elgible,调用GC.Collect()当然不会帮助,很可能会让事情变得更糟(由占用CPU没事的时候非常有用,可以收集)。

You don't generally need to do anything. 您通常不需要执行任何操作。

If the object is no longer referenced then it's a candidate for collection. 如果该对象不再被引用,则它是一个候选集合。 (And, conversely, if the object is still referenced then it's not a candidate for collection, however you "prepare" it.) (相反,如果仍引用该对象,则该对象不是收集对象,但是您可以“准备”该对象。)

You need to clean up any unmanaged resources like database connections etc. 您需要清理所有非托管资源,例如数据库连接等。
Typically by implementing IDisposable and call Dispose . 通常通过实现IDisposable并调用Dispose

If you have a finalizer you should call GC.SuppressFinilize . 如果您有终结器,则应致电GC.SuppressFinilize

The rest is cleaned up by the garbage collector. 其余的由垃圾收集器清理。

Edit: 编辑:
And, oh, naturally you need to release all references to your object. 而且,哦,自然地,您需要释放对对象的所有引用。

But , and here is this big but. 但是 ,这是很大的。 Unless you have a very very special case you don't need to call GC.Collect. 除非您有非常特殊的情况,否则不需要调用GC.Collect。 You probably forgets to release some resources or references, and GC.Collect won't help you with that. 您可能会忘记释放一些资源或参考,而GC.Collect将无法为您提供帮助。 Make sure you call Dispose on everything Disposable (preferably with the using-pattern). 确保对所有Disposable(最好使用using模式)调用Dispose

You should probably pick up a memory profiler like Ants memory profiler and look where all your memory has gone. 您可能应该选择像Ants内存探查器这样的内存探查器,并查看所有内存都去了哪里。

If you have no more direct reference to an object, and you're running out of memory, GC should do this automatically. 如果没有更多直接引用对象,并且内存不足,GC应该自动执行此操作。 Do make sure you call .Dispose() on your datacontext. 确保确保在数据上下文上调用.Dispose()。

Calling GC.Collect will hardly ever prevent you from getting OutOfMemory exceptions, because .NET will call GC.Collect itself when it is unable to create a new object due to OOM. 调用GC.Collect几乎不会阻止您获得OutOfMemory异常,因为.NET因OOM而无法创建新对象时,它将调用GC.Collect本身。 There is only one scenario where I can think of and that is when you have unreferenced objects that are registered in the finalizable queue. 我只能想到一种情况,那就是当您在未终结的队列中注册了未引用的对象时。 When these objects reference many other objects it can cause a OOM. 当这些对象引用许多其他对象时,可能会导致OOM。 The solution to this problem is actually not to call GC.Collect but to ensure that those objects are disposed correctly (and implement the dispose pattern correctly when you created those objects). 解决此问题的方法实际上不是调用GC.Collect而是确保正确放置了这些对象(并在创建这些对象时正确地实现了放置模式)。

Using GC.Collect in general 一般使用GC.Collect

Since you are trying to get rid of a very large collection, it's totally valid to use GC.Collect(). 由于您试图摆脱一个非常大的集合,因此使用GC.Collect()是完全有效的。 From the Microsoft docs : Microsoft文档

... since your application knows more about its behavior than the runtime does, you could help matters by explicitly forcing some collections. ...由于您的应用程序比运行时更了解其行为,因此可以通过显式强制某些集合来帮助解决问题。 For example, it might make sense for your application to force a full collection of all generations after the user saves his data file. 例如,在用户保存数据文件之后,强制应用程序的所有世代都可能对您的应用程序有意义。

"Preparing" your objects “准备”您的对象

From the excellent Performance Considerations for Run-Time Technologies in the .NET Framework (from MSDN): .NET Framework中的运行时技术出色的性能考虑 (来自MSDN):

If you keep a pointer to a resource around, the GC has no way of knowing if you intend to use it in the future. 如果您保持指向资源的指针,则GC无法知道您将来是否打算使用它。 What this means is that all of the rules you've used in native code for explicitly freeing objects still apply, but most of the time the GC will handle everything for you. 这意味着您在本机代码中用于显式释放对象的所有规则仍然适用,但是大多数情况下,GC会为您处理所有事情。

So, to ensure it's ready for GC, Make sure that you have no references to the objects you wish to collect (eg in collections, events, etc...). 因此,要确保已准备好将其用于GC,请确保您没有对要收集的对象的引用(例如,在收集,事件等中)。 Setting the variable to null will mean it's ready for collection before the variable goes out of scope. 将变量设置为null意味着在变量超出范围之前可以进行收集。

Also any object which implements IDisposable should have it's Dispose() method called to clean up unmanaged resources. 同样,任何实现IDisposable的对象都应调用其Dispose()方法来清理非托管资源。

Before you use GC.Collect 使用GC.Collect之前

Since it looks like your application is a server, using the Server GC may resolve your issue. 由于您的应用程序看起来像是服务器,因此使用Server GC可能会解决您的问题。 It will likely run more often and be more performant in a multi-processor scenario. 在多处理器方案中,它可能会更频繁地运行并且性能更高。

The server GC is designed for maximum throughput, and scales with very high performance. 服务器GC旨在实现最大吞吐量,并具有很高的性能进行扩展。

See the Choosing Which Garbage Collector to Use within Performance Considerations for Run-Time Technologies in the .NET Framework (from MSDN): 请参阅在.NET Framework中运行时技术的性能考虑因素中 选择使用哪个垃圾收集器 (来自MSDN):

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM