views:

423

answers:

8

Is there a way to invoke the garbage collector on a specific object within managed memory from an application?

e.g. (in pseudo-code)

Read myString from file;
perform arbitrary operation on myString;
invoke garbage-collector to remove myString
+7  A: 

GC.Collect() it'll tell it to run a collection. But, it won't collect specific objects. The GC is non-deterministic in relation to which objects are collected or not and when.

Qberticus
Furthermore, you don't want it to be deterministic. The GC knows more than you do about when to collect your garbage. The only exception is when your object holds native resources or disposable objects, in which case you should be sure to implement IDisposable.
JSBangs
@Mark: However, it's better to control this via AddMemoryPressure/RemoveMemoryPressure, and still not call GC.Collect(). If you're tracking non-managed memory resources, AddMemoryPressure is the way to let the GC "know" about it - it's still better to let it decide.
Reed Copsey
+4  A: 

There is a Collect method on the Garbage collector, but it should be avoided 99.999% of the time for performance reasons. It's hard to predict the right time to clean up those objects.

http://msdn.microsoft.com/en-us/library/system.gc.collect.aspx

Matthew Vines
+4  A: 

Currently* there is no managed API to invoke the GC on a specific object.

at Dec 17, 2009: .NET 3.5 SP1 and .NET 4.0 Beta 2 do not have it.

Michael Damatov
A: 

To the best of my knowledge it's not possible to be this specific with collection with C#.

It's often cited as one of the cons of C# compared to C/C++.

That said, it would be interesting to know why you want to do this, it does sounds a little like premature performance work. Lots of great advice against this in interesting book I'm reading now, "Coders at Work".

dove
A: 

You shouldn't need it, if it is a string.
It will be collected, when you make sure that there are no references hanging on to it.

To force garbage collection, you could create a class that implements IDisposable interface, provide necessary implementation, use that class in the code & release it by calling Dispose on it.

e.g.

using (WrapsTheStringAndIsDisposable blah = new WrapsTheStringAndIsDisposable())
{
  .....
}

I would go on to say, don't worry about it.

shahkalpesh
But how would you collect the string *within* that class? Sure, you could dispose classes that implement `IDisposable` but strings are disposable that way. I agree with your answer in principle, but it won't work for strings.
Charlie Salts
IDisposable has absolutely nothing to do with managed memory, such as a string. Disposing of a class DOES NOT FREE MEMORY.
Reed Copsey
@Reed Copsey - Exactly... With strings you're at the mercy of the garbage collector.
Charlie Salts
@Reed: I know that Disposing a class does not free memory. It makes the instance eligible for collection. Also, you are incorrect in saying "IDisposable has absolutely nothing to do with managed memory". IDisposable doesn't put restrictions (on the class that implement it) to use unmanaged resources.
shahkalpesh
@Reed: What happens to classes that implement IDisposable and hold string instance inside it? Are they not garbage collected, when dispose is called on the wrapper class instance?
shahkalpesh
@Reed: To your answer "The closest you can do is to unroot your object instance, and then have the garbage collector try to collect everything" - Isn't this what I say already by "It will be collected, when you make sure that there are no references hanging on to it."?
shahkalpesh
@shahkalpesh: It actually does not have anything to do with garbage collection whatsoever. Calling Dispose() does not (typically) make a string elegable for GC. I recommend reading: http://reedcopsey.com/2009/03/20/idisposable-the-oft-misunderstood-and-misused-interface/
Reed Copsey
@shahkalpesh: Yes. Unrooting is making sure there is nothing hanging to it - but that has nothing to do with IDisposable. You're mixing two very different things togehter (memory management and IDisposable, which is about resource, and typically native resource, management).
Reed Copsey
+1  A: 

To add to the other wonderful answers...

Be aware that it is very unlikely you need to actually call GC.Collect() yourself. The garbage collector is very smart and knows when to do its business. See Scott Holden's blog post about GC for more info.

Charlie Salts
+4  A: 

No, and it wouldn't have an effect in any case:

Think about it this way. Say you had a custom class, MyBigMemoryClass, that you wanted to collect an instance of - you'd have to have some way to pass a reference of that to the garbage collector. In a theoretical world, it would be something like:

// Not valid code!
MyBigMemoryClass instance = GetMyInstance();
GC.CollectObject(instance);

However, at this point, you still have a reference to the instance of your class in the instance variable, so the object is still rooted, and not a candidate for garbage collection. The GC would see that its rooted, and leave it be.

The closest you can do is to unroot your object instance, and then have the garbage collector try to collect everything:

MyBigMemoryClass instance = GetMyInstance();
// Do something with instance
instance = null; // Unroot this, so there are (hopefully) no references to it left
GC.Collect(); // Collect everything

That being said, this is typically a very bad idea. It's much better to never call the garbage collector, and allow it to manage the memory for you. There are very few exceptions to this, mostly when working with native code, and those exceptions are typically handled better by using GC.AddMemoryPressure and GC.RemoveMemoryPressure.

Reed Copsey
shahkalpesh
@Reed: I am reading this http://reedcopsey.com/2009/05/01/idisposable-part-5-using-idisposable-classes-in-c/. So, what happens to a string member inside the LoggingLicenseGenerator, when you dispose it?
shahkalpesh
Absolutely nothing. It sits there, until LoggingLicenseGenerator is unrooted, which causes the string to be unrooted. If Dispose set the string reference to null, it ~might~ get collected before that, but that's not really the purpose behind dispose.
Reed Copsey
Calling instance.Dispose() does not unroot instance, though. You'd have to do instance = null;, and also make sure nothing else has a reference to instance - then it (and it's encapsulated string) will be eligable for GC.
Reed Copsey
@Reed: Sir, thats what I meant when I say - wrap it inside a class that implements IDisposable. I know it is crude and hence I said towards the end, don't worry about it.
shahkalpesh
@Reed: "Calling instance.Dispose() does not unroot instance". I suppose, if you have reference (to an instance of class that implements IDisposable) on one of the reference, rest of the references will fail (ofcourse, after the GC runs and the IDisposable instance is collected) with ObjectDispoedException, if my understanding is right.
shahkalpesh
Nope. It's never possible to raise ObjectDisposedException on an object after GC - because you can't have a reference to it anymore (so no way to trigger that).
Reed Copsey
shahkalpesh
shahkalpesh
There are many cases like this - They are often used for factored types (you can keep reading my series to see this), but in this case, it's because TextReader implements IDiposable (StringReader's base class) so that derived, specific classes which "read" from native resources will work correctly.
Reed Copsey
A: 

Lately I had a handle overflow problem at work. In Windows, one process can only have 10 000 handles max. Security Issues.

Any way here is what worked out: - Call dispose on controls that are closed or hidden - Call GC.Collect - If a call occurs on a control that was disposed, but its needed again, recreate it.

Basic usage is with the tab controls. We have many of them. Each tab control holds around 10-20 tabs a user can click on. But there is only 1 tab selected at the moment. If the handle count is near 10 000, we clear all objects that are on hidden tabs.

On a tab show we recreate them if they are needed.

Turek
WinForm controls implement `IDisposable` because the `hWnd` property is an unmanaged resource. If you explicitly call `Dispose` on a control, it releases the window handle. The only place where garbage collection enters the picture is that if you *don't* call `Dispose` on a control, the window handle doesn't get released *until* the GC calls `Finalize` on it prior to destroying it. I know this because I fixed this exact problem in my application, and I don't call `GC.Collect()` ever.
Robert Rossney
Incidentally, you might find the least-recently-used cache collection I implemented to be useful. Just add a control to the cache whenever the user visits it, and when you need to start disposing controls, remove and dispose the `Oldest`. It's at http://code.google.com/p/csharp-lru-cache/.
Robert Rossney