-1

I'm still somewhat confused by C#'s garbage collector. Documentation states that an object is garbage collected when there are no more references pointing to it.

So my question is, why is this object not immediately garbage collected? There is no reference to it. Let's assume that the background class itself creates no references either.

public void StartGame() {
   // the background instance is created, but no reference is kept:
   new Background("landscape.png", speed);
}
Kokodoko
  • 26,167
  • 33
  • 120
  • 197
  • 1
    `when there are no more references...` does not mean *as soon as there are no more references...* – Ňɏssa Pøngjǣrdenlarp Mar 22 '15 at 16:29
  • 4
    An object is *eligible* for collection when there are no more references to it. The garbage collector only runs when it needs to free up some memory, not immediately each time an object becomes eligible for collection. – Michael Liu Mar 22 '15 at 16:30
  • So my background might randomly disappear any time, because I have no reference? I ask this because I have literally never seen that happen. – Kokodoko Mar 22 '15 at 16:46
  • 1
    The answer to your question depends entirely on what the `Background` ctor does. – Brian Snow Mar 22 '15 at 17:03
  • 1
    "Let's assume that the background class itself creates no references either." -- Then what difference does it make whether the instance gets garbage collected? Pretty much the only way your code makes sense is if it does create references to itself. –  Mar 22 '15 at 17:12
  • I see your point. It's hard to phrase the question correctly without adding irrelevant code. But if I understand correctly, the above background class COULD be garbage collected if it were empty? It might randomly disappear from my game any time? That's ultimately what I want to know, and perhaps I should have phrased that differently. – Kokodoko Mar 22 '15 at 17:41
  • Without any incoming references it couldn't be _in_ your game to begin with. You're still missing the point. – H H Mar 22 '15 at 18:33
  • Perhaps my question should have been: if the above background class (without a reference) is running code, will it be GC'd? I found that most docs are a bit fuzzy about what exactly prevents GC apart from keeping a 'hard' reference in a main class. – Kokodoko Mar 23 '15 at 11:15
  • Normal usage is much simpler than you think. .NET guarantees memory-safety: whenever your code uses a reference, the referenced object cannot have been collected. The finer points are [a little more complicated](http://stackoverflow.com/a/23990365/60761) but the guarantee still holds. – H H Mar 23 '15 at 23:49

4 Answers4

2

What you are describing is of more resemblance to memory management through reference counting, that checks whether to free the memory when the reference counter is accessed, typically when the referencing object is constructed or destroyed.

Garbage collection is a slightly different concept. Directly freeing the objects in GC-powered environments is typically not allowed or not recommended. Instead, a garbage collector is run occasionally (the runtime decides when to do that), that finds all the no longer referenced objects and frees the memory taken by these. The point is, you should not bother (because you can do nothing about it) when exactly it's going to happen.

D-side
  • 9,150
  • 3
  • 28
  • 44
  • Yep, but in the above example, would my background be eligible for garbage collection, and hence randomly disappear from my game? I have never seen that happen, although the documentation suggests that it could happen. – Kokodoko Mar 22 '15 at 16:54
  • @Kokodoko that's unlikely. A running background task should be known to a scheduler that allocates execution time to threads. As long as a thread lives, the scheduler references it and keeps it intact. – D-side Mar 22 '15 at 17:06
  • Aha, so as long as the background class itself is executing code it won't be garbage collected? That clarifies a lot! – Kokodoko Mar 22 '15 at 17:44
2

The garbage collector is like the garbage truck that drives around your neighborhood. You can't will it to pick up your trash once you put it on the side of the street. You have to wait for it to come on its own terms.

Garbage collectors are theoretically really simple: stop the world, determine what's no longer being used, collect, resume the world. But because this takes time, developers use complex algorithms to decide when the collector kicks in and what it collects, to make your program run as smoothly as possible. Some garbage is usually not a problem that affects your program.

If you are expecting your object to be collected as soon as it goes out of scope, and you're probably using a finalizer to test this. Don't! Instead, implement IDisposable and call the Dispose method yourself, as soon as you're done with it. You can't rely on the garbage collector to collect your object at any time, if ever. That's why the BCL I/O classes all implement IDisposable for flushing streams, closing connections and cleaning up memory.

Or if you want to keep your object around, you need to keep an (indirect) reference to it. The object might just be collected on the next garbage collection cycle.


Well, there's one not recommended way to force the garbage truck to collect your garbage, using GC.Collect:

GC.Collect();

This will temporary stop your program to collect all garbage. However, this might still not clear your Background object while it's living on the stack or some other place. You can't predict where the runtime will put your object and when it will release it, so be sure to at least exit the method that created the object before testing whether it is collected using GC.Collect.

Daniel A.A. Pelsmaeker
  • 47,471
  • 20
  • 111
  • 157
  • Thanks! I know that you can't force the garbage truck to stop by your door, but in the above example, would it ever? My background class keeps happily running in my game, it's never deleted at all. – Kokodoko Mar 22 '15 at 16:55
1

The garbage collector in C# is invoked only at certain moments and is generational. This means that an object that has no reference at the first pass of the GC will be upgraded by 1 generation. The lowest generation is garbage collected way more often than the rest.

You may read this article to understand more: https://msdn.microsoft.com/en-us/library/ee787088%28v=vs.110%29.aspx

You may alternatively call the GC.Collect method, but this is not recommended as .NET is pretty much able to handle its own memory and invoking this method kinda defeats the whole purpose.

gretro
  • 1,934
  • 15
  • 25
  • Thanks, but perhaps I didn't phrase my question strictly enough. I want to know if I need to keep a reference to prevent the background from suddenly (and randomly) disappearing from my game. Would you say that in my example above, the background could just disappear at any moment, when the GC decides that it needs the memory for other things? – Kokodoko Mar 22 '15 at 16:51
  • 1
    @Kokodoko - that's a non-question. Your background won't show (unless its constructor regiters itself). In-use == safe from GC. – H H Mar 22 '15 at 17:17
1

Well if you want to check if an object will be garbage collected you can do the following to test in your code if it is eligible for collection by doing the following.

Modify your method a little for testing alternatively you could make reference a field that is set in the StartGame Method.

public void StartGame(out WeakReference reference)
{
    reference = new WeakReference(new Background("landscape.png", speed));
}

After your method is called you can do the following to see if it is eligible for collection.

WeakReference reference;
StartGame(out reference);
GC.Collect();
GC.WaitForPendingFinalizers();
if (reference.IsAlive)
{
    Console.WriteLine("Background is not eligible for collection");
}

This is only for testing, you shouldn't be calling the Garbage collector otherwise.

Bilal Bashir
  • 1,443
  • 14
  • 18