I'm trying to build my first unit tests and have a class that increments and decrements an instance counter in it's constructor and destructor respectively. I have a test to make sure this works but it fails, it seems that other instances of the class from my other tests aren't having their destructor called when they go out of scope.
public class Customer
{
public Customer()
{
++InstanceCount;
}
public Customer(int customerId)
{
CustomerId = customerId;
++InstanceCount;
}
~Customer()
{
--InstanceCount;
}
public static int InstanceCount { get; private set; }
}
[TestClass]
public class CustomerTest
{
[TestMethod]
public void FullNameLastNameEmpty()
{
//--Arrange
Customer customer = new Customer {FirstName = "John"};
const string expected = "John";
//--Act
string actual = customer.FullName;
//--Assert
Assert.AreEqual(expected, actual);
}
[TestMethod]
public void StaticTest()
{
//--Arrange
Customer[] customers =
{
new Customer {FirstName = "John"},
new Customer {FirstName = "Jane"},
new Customer {FirstName = "Jeff"}
};
//--Act
//--Assert
Assert.AreEqual(3, Customer.InstanceCount);
}
}
I'm not passing a reference anywhere so customer should be deallocated but it is not, I've even tried calling GC.Collect() at the start of StaticTest() to force calls to the destructor but still no luck.
Could someone explain why this is happening and how to fix it.
C# is not C++. Destuctors, or rather finalizers, are a feature for very specific purposes, namely for handling the disposal of unmanaged resources held by your objects. Stuffing program logic into finalizers is one of the few very bad ideas you can have with C#. Why? Here's a quick rundown:
There is no guarantee on when an object will be collected when it goes out of scope.
Heck, there is no guarantee that a collection ever occurs if there's no memory pressure.
There's no guarantee on the ordering in which object finalizer's run.
There's no guarantee on when an object finalizer runs - could be right after it goes out of scope, could be a minute later.
Heck, there is no guarantee a finalizer ever runs.
There's no guarantee that, if it runs, it runs after your ctor completed. So in your case you could end up decrementing the instance count without incrementing it. Granted, this is unlikely to actually happen, but it just might.
Oh, it also negatively affects the performance of your entire app, but that's pretty minor compared to the evilness above.
Basically, when using finalizers, everything you know is wrong. Finalizers are so evil that there's a part two of that!
The guideline for using finalizers is - don't. Even if you are an experienced C# developer, the chances that you actually need a finalizer are very slim, while chances that you'll get something wrong while writing it are huge. If you're forced to work with unmanaged resources, follow the guidelines and use a SafeHandle.
If your requirement is to count instances, your best bet is using the IDisposable pattern. This is a cooperative way of doing that, meaning that the calling code will have to actually Dispose() of your object for the count to decrement. But it can't be any other way. The bottom line is that in C# there is no reliable way of doing something the moment the last reference to an object goes out of scope.
UPDATE:
I hope that I have discouraged you from ever writing finalizers, ever. Seriously, unless you're a pro and know for sure that you absolutely need the finalizer and can describe everything that happens on the CLR level with them, just don't. However. There is an ugly hack you can employ to get what you want. These two spells:
GC.Collect();
GC.WaitForPendingFinalizers();
should force a collection to happen, which will put your objects on the finalizer queue, and wait for all of them to finish. If you run that after every test case, it should give you the behaviour you expected. But please, for the sake of us all, don't use that in serious code. I've just shown you a terribly sharp, double-edged blade. Without any handle. That's on fire. That second method isn't even guaranteed to terminate.
someone else already mentioned the difference between c++ destructor and c# finalizer so I am not going to repeat that.
In case you are wondering why your Test failed even after calling GC: Your variable never went out of scope. customers array holds references to all 3 Customer instances and the scope for customers array is StaticTest function. It will only be out of scope once StaticTest returns.
class Program
{
static void Create()
{
Customer[] customers =
{
new Customer (),
new Customer (),
new Customer (),
};
}
static void Main(string[] args)
{
Create();
Console.WriteLine($"Before GC Count: {Customer.InstanceCount}");
GC.Collect(0);
GC.WaitForPendingFinalizers();
Console.WriteLine($"After GC Count: {Customer.InstanceCount}");
}
}
This will give you the expected result
Before GC Count: 3
After GC Count: 0
adding to all these answers, below are my two cents.
If its c#,
try add IDispoable to your class and create/override the dispose() method in your class. Then handle the decrement logic there.
try to use the Test Teardown/finalize method and Test initialize methods to appropriately utilize the dispose of objects after every test case is completed.
In a real world scenario, once the object's scope is done, if we want to dispose them off, calling them explicitly by implementing IDispoable would make that object a candidate for Garbage collector. if it is what your intent is.
Related
(I don't even know whether my question makes sense at all; it is just something that I do not understand and is spinning in my head for some time)
Consider having the following class:
public class MyClass
{
private int _myVar;
public void DoSomething()
{
// ...Do something...
_myVar = 1;
System.Console.WriteLine("Inside");
}
}
And using this class like this:
public class Test
{
public static void Main()
{
// ...Some code...
System.Console.WriteLine("Before");
// No assignment to a variable.
new MyClass().DoSomething();
// ...Some other code...
System.Console.WriteLine("After");
}
}
(Ideone)
Above, I'm creating an instance of a class without assigning it to a variable.
I fear that the garbage collector could delete my instance too early.
My naive understanding of garbage collection is:
"Delete an object as soon as no references point to it."
Since I create my instance without assigning it to a variable, this condition would be true. Obviously the code runs correct, so my asumption seems to be false.
Can someone give me the information I am missing?
To summarize, my question is:
(Why/why not) is it safe to instantiate a class without asigning it to a variable or returning it?
I.e. is
new MyClass().DoSomething();
and
var c = new MyClass();
c.DoSomething();
the same from a garbage collection point-of-view?
It's somewhat safe. Or rather, it's as safe as if you had a variable which isn't used after the method call anyway.
An object is eligible for garbage collection (which isn't the same as saying it will be garbage collected immediately) when the GC can prove that nothing is going to use any of its data any more.
This can occur even while an instance method is executing if the method isn't going to use any fields from the current execution point onwards. This can be quite surprising, but isn't normally an issue unless you have a finalizer, which is vanishingly rare these days.
When you're using the debugger, the garbage collector is much more conservative about what it will collect, by the way.
Here's a demo of this "early collection" - well, early finalization in this case, as that's easier to demonstrate, but I think it proves the point clearly enough:
using System;
using System.Threading;
class EarlyFinalizationDemo
{
int x = Environment.TickCount;
~EarlyFinalizationDemo()
{
Test.Log("Finalizer called");
}
public void SomeMethod()
{
Test.Log("Entered SomeMethod");
GC.Collect();
GC.WaitForPendingFinalizers();
Thread.Sleep(1000);
Test.Log("Collected once");
Test.Log("Value of x: " + x);
GC.Collect();
GC.WaitForPendingFinalizers();
Thread.Sleep(1000);
Test.Log("Exiting SomeMethod");
}
}
class Test
{
static void Main()
{
var demo = new EarlyFinalizationDemo();
demo.SomeMethod();
Test.Log("SomeMethod finished");
Thread.Sleep(1000);
Test.Log("Main finished");
}
public static void Log(string message)
{
// Ensure all log entries are spaced out
lock (typeof(Test))
{
Console.WriteLine("{0:HH:mm:ss.FFF}: {1}",
DateTime.Now, message);
Thread.Sleep(50);
}
}
}
Output:
10:09:24.457: Entered SomeMethod
10:09:25.511: Collected once
10:09:25.562: Value of x: 73479281
10:09:25.616: Finalizer called
10:09:26.666: Exiting SomeMethod
10:09:26.717: SomeMethod finished
10:09:27.769: Main finished
Note how the object is finalized after the value of x has been printed (as we need the object in order to retrieve x) but before SomeMethod completes.
The other answers are all good but I want to emphasize a few points here.
The question essentially boils down to: when is the garbage collector allowed to deduce that a given object is dead? and the answer is the garbage collector has broad latitude to use any technique it chooses to determine when an object is dead, and this broad latitude can lead to some surprising results.
So let's start with:
My naive understanding of garbage collection is: "Delete an object as soon as no references point to it."
This understanding is wrong wrong wrong. Suppose we have
class C { C c; public C() { this.c = this; } }
Now every instance of C has a reference to it stored inside itself. If objects were only reclaimed when the reference count to them was zero then circularly referenced objects would never be cleaned up.
A correct understanding is:
Certain references are "known roots". When a collection happens the known roots are traced. That is, all known roots are alive, and everything that something alive refers to is also alive, transitively. Everything else is dead, and eligable for reclamation.
Dead objects that require finalization are not collected. Rather, they are kept alive on the finalization queue, which is a known root, until their finalizers run, after which they are marked as no longer requiring finalization. A future collection will identify them as dead a second time and they will be reclaimed.
Lots of things are known roots. Static fields, for example, are all known roots. Local variables might be known roots, but as we'll see below, they can be optimized away in surprising ways. Temporary values might be known roots.
I'm creating an instance of a class without assigning it to a variable.
Your question here is a good one but it is based on an incorrect assumption, namely that a local variable is always a known root. Assigning a reference to a local variable does not necessarily keep an object alive. The garbage collector is allowed to optimize away local variables at its whim.
Let's give an example:
void M()
{
var resource = OpenAFile();
int handle = resource.GetHandle();
UnmanagedCode.MessWithFile(handle);
}
Suppose resource is an instance of a class that has a finalizer, and the finalizer closes the file. Can the finalizer run before MessWithFile? Yes! The fact that resource is a local variable with a lifetime of the entire body of M is irrelevant. The runtime can realize that this code could be optimized into:
void M()
{
int handle;
{
var resource = OpenAFile();
handle = resource.GetHandle();
}
UnmanagedCode.MessWithFile(handle);
}
and now resource is dead by the time MessWithFile is called. It is unlikely but legal for the finalizer to run between GetHandle and MessWithFile, and now we're messing with a file that has been closed.
The correct solution here is to use GC.KeepAlive on the resource after the call to MessWithFile.
To return to your question, your concern is basically "is the temporary location of a reference a known root?" and the answer is usually yes, with the caveat that again, if the runtime can determine that a reference is never dereferenced then it is allowed to tell the GC that the referenced object might be dead.
Put another way: you asked if
new MyClass().DoSomething();
and
var c = new MyClass();
c.DoSomething();
are the same from the point of view of the GC. Yes. In both cases the GC is allowed to kill the object the moment that it determines it can do so safely, regardless of the lifetime of local variable c.
The shorter answer to your question is: trust the garbage collector. It has been carefully written to do the right thing. The only times you need to worry about the GC doing the wrong thing are scenarios like the one I laid out, where timing of finalizers is important for the correctness of unmanaged code calls.
Of course, GC is transparent to you and no early collection can ever happen. So I guess you want to know the implementation details:
An instance method is implemented like a static method with an additional this parameter. In your case the this value lives in registers and is passed like that into DoSomething. The GC is aware what registers contain live references and will treat them as roots.
As long as DoSomething might still use the this value it stays live. If DoSomething never uses instance state then indeed the instance can be collected while a method call is still running on it. This is unobservable, therefore safe.
As long as you're talking about a single threaded environment, you're safe. Fun things only start to happen if you're starting a new thread inside the DoSomething method, and even more fun happens if your class has a finalizer. The key thing to understand here is that a lot of the contracts between you and the runtime / optimizer / etc. are valid only in a single thread. This is one of the things that has disastrous results when you start programming on multiple threads in a language that isn't primaririly multi-threading oriented (yes, C# is one of those languages).
In your case, you're even using the this instance, which makes unexpected collection even less likely while still inside that method; in any case, the contract is that on a single thread, you can't observe the difference between the optimized and unoptimized code (apart from memory usage, speed, etc., but those are the "free lunch").
I have a class:
public class SomeClass {
public int I;
public SomeClass(int input) {
I = input;
Console.WriteLine("I = {0}", I);
}
~SomeClass() {
Console.WriteLine("deleted");
}
public void Foo() {
Thread.Sleep(1000);
Console.WriteLine("Foo");
}
}
and this program:
class Program {
static void Main(string[] args) {
new Thread(() => {
Thread.Sleep(100);
GC.Collect();
}) { IsBackground = true }.Start();
new SomeClass(10).Foo();
// The same as upper code
// var t = new SomeClass(10);
// t.Foo();
}
}
When i run this code in Debug mode, i have next result:
I = 10
Foo
deleted
but, when i change mode to Release, result changes to:
I = 10
deleted
Foo
As i understand, there is difference with call and callvirt: when optimization starts in Release mode, compiler look at Foo method and can't find any reference to SomeClass in this method, and that's why this method calls as static method by address, and garbage collector could collect this object.
Otherwise, if i change Foo method (for example, add Console.WriteLine(I) into this method), compiler won't decide to call this method as call and it should be called by pointer to instance with callvirt and garbage collector won't collect this object.
Can you please explain more clearly, what's going on here (why GC could collect object and if it's so, how does method calls).
I doubt that it's really anything to do with call and callvirt.
I strongly suspect it's simply because you're not using any fields within SomeClass.Foo. The garbage collector is free to collect an object when it is certain that none of the data will be referenced again - so no code is going to look at any references to the object, or any fields within the object.
Basically, if you write a finalizer and you need to ensure that the object isn't finalized while methods within that object are running, you need to be very careful. You can use GC.KeepAlive(this) at the end of methods, as one approach, but it's a bit ugly. I would personally try very hard to avoid needing a finalizer at all, if you can. I can't remember the last time I wrote one. (See Joe Duffy's blog for more.)
When there's a debugger attached, the GC is much less aggressive about what it can collect - after all, if you can break into the debugger at any point and inspect the fields of any object that is the target of a running instance method, that removes the possibility of garbage collecting those objects.
When you're debugging, the whole system1 extends the lifetime of objects beyond their natural lifetime.
So, when a thread is executing this method:
public void Foo() {
Thread.Sleep(1000);
Console.WriteLine("Foo");
}
This method makes no use of this. So when not debugging, after this method has started running, it doesn't require the object to exist any longer.
However, when debugging, you might have set a breakpoint on that Console.WrtieLine method, and from there decide to inspect this. So the system conspires to keep this alive (as well as any local variables which are no longer used within the body of a method).
1This old presentation shows how the JIT and GC actually work together to work out which references are live (see slide 30 onwards). It is my understanding that the JIT does more work to help out with debugging - by not reusing local variable slots which it could (so values are still visible) and by informing the GC that all variables are alive throughout the method, rather than the more piecemeal analysis it can provide.
Here is example program that exhibits surprising finalization behavior:
class Something
{
public void DoSomething()
{
Console.WriteLine("Doing something");
}
~Something()
{
Console.WriteLine("Called finalizer");
}
}
namespace TestGC
{
class Program
{
static void Main(string[] args)
{
var s = new Something();
s.DoSomething();
GC.Collect();
//GC.WaitForPendingFinalizers();
s.DoSomething();
Console.ReadKey();
}
}
}
If I run the program, what gets printed is:
Doing something
Doing something
Called finalizer
This appears as expected. Because there is a reference to s after the call to GC.Collect(), s is not a garbage.
Now remove comments from the line //GC.WaitForPendingFinalizers();
build and run the program again.
I would expect nothing to change in the output. This because I read that if object is found to be a garbage and it has a finalizer, it will be put on finalizer queue. Since object is not a garbage, then is seems logical that it should not be put on finalizer queue. Thus the line commented out should do nothing.
However, the output of the program is:
Doing something
Called finalizer
Doing something
Can somebody help my understanding of why finalizer gets called?
I can't reproduce the problem on my laptop, but your DoSomething method doesn't use any fields within the object. That means that the object can be finalized even while DoSomething is running.
If you change your code to:
class Something
{
int x = 10;
public void DoSomething()
{
x++;
Console.WriteLine("Doing something");
Console.WriteLine("x = {0}", x);
}
~Something()
{
Console.WriteLine("Called finalizer");
}
}
... then I suspect you will always see DoingSomething printed twice before "Called finalizer" - although the final "x = 12" may be printed after "Called finalizer".
Basically, finalization can be somewhat surprising - I very rarely find myself using it, and would encourage you to avoid finalizers wherever possible.
Jon's answer is of course correct. I would add to it that the C# specification calls out that the compiler and runtime are allowed to (but not required to) notice that the reference contained in a local variable is never again dereferenced, and at that point the garbage collector is allowed to treat the object as dead if the local is the last living reference. Therefore the object can be collected and the finalizer run even though there appears to be a reference in a living local variable. (And similarly the compiler and runtime are allowed to make locals live longer if they so choose.)
Given this fact you can end up in bizarre situations. For example, it is possible for a finalizer to be executing on the finalizer thread while the object's constructor is running on a user thread. If the runtime can determine that "this" is never dereferenced again then the object can be treated as dead the moment the constructor is done mutating fields of "this". If the constructor then does additional work -- say, mutating global state -- then that work can be done as the finalizer is running.
This is just yet another reason why writing a correct finalizer is so difficult that you probably should not do so. In a finalizer everything you know is wrong. Everything you're referring to could be dead, you're on a different thread, the object might not be fully constructed, possibly none of your program invariants are actually maintained.
Your DoSomething() is so trivial that it's likely to get inlined. After it's been inlined, there's nothing that still has a reference to the object, so there's nothing preventing it from being garbage collected.
GC.KeepAlive() is designed specifically for this scenario. It can be used if you want to prevent an object from being garbage collected. It does nothing, but the garbage collector doesn't know that. Call GC.KeepAlive(s); at the end of Main to prevent it from being finalised earlier.
Recently, while taking an introductory unit focused on Object Oriented programming, I was introduced to the Garbage Collector in C#, and that it's role is to "clean up" objects that are no longer being referenced. Then I was introduced to destructors, and how they're called just before the object is deleted.
Naturally, I got thinking, but I never remembered to ask the lecturer about it; what will happen if you create an instance of a class within the destructor of the same class?
C# example
class Person{
~Person(){
Person p = new Person();
Console.WriteLine("Person destroyed");
}
}
class Program{
static void Main(string[] args){
Person p = new Person();
}
}
I would like to approach this from a more theoretical point of view, so I'm reluctant (at this stage) to try it since I probably wouldn't understand anyway, but I have a few theories. Besides, I'm not at my regular computer right now ;)
Person.~Person() is going to recurse, as each time the new Person is created, it's going to call its destructor and create a new Person ad infinitum, or until some kind of memory-related exception occurs. Subsequently, main will never terminate.
The compiler will complain (adding this option to every scenario seems like a good idea anyway).
Somehow, some kind of "destructor skipping" will occur. ie. object destruction wouldn't be called sequentially, so neither would the constructor.
Now for a similarly related question. If the Garbage Collector's role is to delete the objects that are no longer referenced/needed, how would a situation like the one above be handled in an environment without a Garbage Collector - say, C++?
There's no real mystery here I think.
It won't 'recurse' as such - you're just chucking a new object on the managed heap which is immediately dereferenced; thus making it a candidate for garbage collection.
Eventually the garbage collector will come round again, triggering the operation again etc.
That's not recursion - more like a chain. But ultimately each Person will be removed from memory.
And, after a while the Garbage collector will send you an email complaining that you're not playing fair.
As for C++, well my guess is a stack overflow, since construction/destruction is happening there and then, and a very sulky computer afterwards.
If your next logical thought is 'shouldn't the runtime/language stop this from happening?' - no. The language or runtimes in question are not there to stop you doing something that would otherwise be considered ill-advised; it trusts you, the programmer, to make sure you're not doing that.
That said - in an application shutdown scenario (re your comment below) the .Net runtime is going to act out of self-interest and will ultimately stop processing these finalizers to enact a shutdown. Finalizers are for your benefit, not the runtime's.
A more interesting point to make is that an object can actually resurrect itself in the finalizer!
class Foo
{
static public List<Foo> ZombieFoos = new List<Foo>;
~Foo()
{
ZombieFoos.Add(this);
// Now there is a reference to this instance again (in the list)..
// The GC will not reclaim this instance.. huzzah we have been resurrected!!
}
}
Not even remotely recommended...
You could, in fact, cause system to be 99.9 time in GC. Just acquire sufficient amount of memory by every Person object for GC to trigger Heap 0 collection.
I have a timer in C# which executes some code inside it's method. Inside the code I'm using several temporary objects.
If I have something like Foo o = new Foo(); inside the method, does that mean that each time the timer ticks, I'm creating a new object and a new reference to that object?
If I have string foo = null and then I just put something temporal in foo, is it the same as above?
Does the garbage collector ever delete the object and the reference or objects are continually created and stay in memory?
If I just declare Foo o; and not point it to any instance, isn't that disposed when the method ends?
If I want to ensure that everything is deleted, what is the best way of doing it:
with the using statement inside the method
by calling dispose method at the end
by putting Foo o; outside the timer's method and just make the assignment o = new Foo() inside, so then the pointer to the object is deleted after the method ends, the garbage collector will delete the object.
1.If I have something like Foo o = new Foo(); inside the method, does that
mean that each time the timer ticks,
I'm creating a new object and a new
reference to that object?
Yes.
2.If I have string foo = null and then I just put something temporal in foo,
is it the same as above?
If you are asking if the behavior is the same then yes.
3.Does the garbage collector ever delete the object and the reference or
objects are continually created and
stay in memory?
The memory used by those objects is most certainly collected after the references are deemed to be unused.
4.If I just declare Foo o; and not point it to any instance, isn't that
disposed when the method ends?
No, since no object was created then there is no object to collect (dispose is not the right word).
5.If I want to ensure that everything is deleted, what is the best way of
doing it
If the object's class implements IDisposable then you certainly want to greedily call Dispose as soon as possible. The using keyword makes this easier because it calls Dispose automatically in an exception-safe way.
Other than that there really is nothing else you need to do except to stop using the object. If the reference is a local variable then when it goes out of scope it will be eligible for collection.1 If it is a class level variable then you may need to assign null to it to make it eligible before the containing class is eligible.
1This is technically incorrect (or at least a little misleading). An object can be eligible for collection long before it goes out of scope. The CLR is optimized to collect memory when it detects that a reference is no longer used. In extreme cases the CLR can collect an object even while one of its methods is still executing!
Update:
Here is an example that demonstrates that the GC will collect objects even though they may still be in-scope. You have to compile a Release build and run this outside of the debugger.
static void Main(string[] args)
{
Console.WriteLine("Before allocation");
var bo = new BigObject();
Console.WriteLine("After allocation");
bo.SomeMethod();
Console.ReadLine();
// The object is technically in-scope here which means it must still be rooted.
}
private class BigObject
{
private byte[] LotsOfMemory = new byte[Int32.MaxValue / 4];
public BigObject()
{
Console.WriteLine("BigObject()");
}
~BigObject()
{
Console.WriteLine("~BigObject()");
}
public void SomeMethod()
{
Console.WriteLine("Begin SomeMethod");
GC.Collect();
GC.WaitForPendingFinalizers();
Console.WriteLine("End SomeMethod");
}
}
On my machine the finalizer is run while SomeMethod is still executing!
The .NET garbage collector takes care of all this for you.
It is able to determine when objects are no longer referenced and will (eventually) free the memory that had been allocated to them.
Objects are eligable for garbage collection once they go out of scope become unreachable (thanks ben!). The memory won't be freed unless the garbage collector believes you are running out of memory.
For managed resources, the garbage collector will know when this is, and you don't need to do anything.
For unmanaged resources (such as connections to databases or opened files) the garbage collector has no way of knowing how much memory they are consuming, and that is why you need to free them manually (using dispose, or much better still the using block)
If objects are not being freed, either you have plenty of memory left and there is no need, or you are maintaining a reference to them in your application, and therefore the garbage collector will not free them (in case you actually use this reference you maintained)
Let's answer your questions one by one.
Yes, you make a new object whenever this statement is executed, however, it goes "out of scope" when you exit the method and it is eligible for garbage collection.
Well this would be the same as #1, except that you've used a string type. A string type is immutable and you get a new object every time you make an assignment.
Yes the garbage collector collects the out of scope objects, unless you assign the object to a variable with a large scope such as class variable.
Yes.
The using statement only applies to objects that implement the IDisposable interface. If that is the case, by all means using is best for objects within a method's scope. Don't put Foo o at a larger scope unless you have a good reason to do so. It is best to limit the scope of any variable to the smallest scope that makes sense.
Here's a quick overview:
Once references are gone, your object will likely be garbage collected.
You can only count on statistical collection that keeps your heap size normal provided all references to garbage are really gone. In other words, there is no guarantee a specific object will ever be garbage collected.
It follows that your finalizer will also never be guaranteed to be called. Avoid finalizers.
Two common sources of leaks:
Event handlers and delegates are references. If you subscribe to an event of an object, you are referencing to it. If you have a delegate to an object's method, you are referencing it.
Unmanaged resources, by definition, are not automatically collected. This is what the IDisposable pattern is for.
Finally, if you want a reference that does not prevent the object from getting collected, look into WeakReference.
One last thing: If you declare Foo foo; without assigning it you don't have to worry - nothing is leaked. If Foo is a reference type, nothing was created. If Foo is a value type, it is allocated on the stack and thus will automatically be cleaned up.
Yes
What do you mean by the same? It will be re-executed every time the method is run.
Yes, the .Net garbage collector uses an algorithm that starts with any global/in-scope variables, traverses them while following any reference it finds recursively, and deletes any object in memory deemed to be unreachable. see here for more detail on Garbage Collection
Yes, the memory from all variables declared in a method is released when the method exits as they are all unreachable. In addition, any variables that are declared but never used will be optimized out by the compiler, so in reality your Foo variable will never ever take up memory.
the using statement simply calls dispose on an IDisposable object when it exits, so this is equivalent to your second bullet point. Both will indicate that you are done with the object and tell the GC that you are ready to let go of it. Overwriting the only reference to the object will have a similar effect.
The garbage collector will come around and clean up anything that no longer has references to it. Unless you have unmanaged resources inside Foo, calling Dispose or using a using statement on it won't really help you much.
I'm fairly sure this applies, since it was still in C#. But, I took a game design course using XNA and we spent some time talking about the garbage collector for C#. Garbage collecting is expensive, since you have to check if you have any references to the object you want to collect. So, the GC tries to put this off as long as possible. So, as long as you weren't running out of physical memory when your program went to 700MB, it might just be the GC being lazy and not worrying about it yet.
But, if you just use Foo o outside the loop and create a o = new Foo() each time around, it should all work out fine.
As Brian points out the GC can collect anything that is unreachable including objects that are still in scope and even while instance methods of those objects are still executing. consider the following code:
class foo
{
static int liveFooInstances;
public foo()
{
Interlocked.Increment(ref foo.liveFooInstances);
}
public void TestMethod()
{
Console.WriteLine("entering method");
while (Interlocked.CompareExchange(ref foo.liveFooInstances, 1, 1) == 1)
{
Console.WriteLine("running GC.Collect");
GC.Collect();
GC.WaitForPendingFinalizers();
}
Console.WriteLine("exiting method");
}
~foo()
{
Console.WriteLine("in ~foo");
Interlocked.Decrement(ref foo.liveFooInstances);
}
}
class Program
{
static void Main(string[] args)
{
foo aFoo = new foo();
aFoo.TestMethod();
//Console.WriteLine(aFoo.ToString()); // if this line is uncommented TestMethod will never return
}
}
if run with a debug build, with the debugger attached, or with the specified line uncommented TestMethod will never return. But running without a debugger attached TestMethod will return.