简体   繁体   中英

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

Scenario

  • Lets say that I've decided I really need to call 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? Or just assigning null to the object itself?

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.
  • 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.

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?
  • My original problem is here - Distributed OutOfMemory Exceptions

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?

I genuinely doubt that GC.Collect() is the answer here; 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).

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 .

If you have a finalizer you should call 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. You probably forgets to release some resources or references, and GC.Collect won't help you with that. Make sure you call Dispose on everything Disposable (preferably with the using-pattern).

You should probably pick up a memory profiler like Ants memory profiler and look where all your memory has gone.

If you have no more direct reference to an object, and you're running out of memory, GC should do this automatically. Do make sure you call .Dispose() on your datacontext.

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. 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. 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).

Using GC.Collect in general

Since you are trying to get rid of a very large collection, it's totally valid to use GC.Collect(). From the Microsoft docs :

... 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):

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. 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.

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...). Setting the variable to null will mean it's ready for collection before the variable goes out of scope.

Also any object which implements IDisposable should have it's Dispose() method called to clean up unmanaged resources.

Before you use GC.Collect

Since it looks like your application is a server, using the Server GC may resolve your issue. 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.

See the Choosing Which Garbage Collector to Use within Performance Considerations for Run-Time Technologies in the .NET Framework (from MSDN):

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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