Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Question about the garbage collector in .NET (memory leak)

I guess this is very basic but since I'm learning .NET by myself, I have to ask this question.

I'm used to coding in C, where you have to free() everything. In C++/.NET, I have read about the garbage collector. From what I understand, when an instance is no longer used (in the scope of the object), it is freed by the garbage collector.

So, having that in mind, I built a little testing application. But, it seems I didn't get something because when doing the same things a few times (like, opening a form, closing it, reopening it, etc), memory leaks. And big time.

I tried to look this up on Google but I didn't find anything good for a beginner.

  1. Is the garbage collector really freeing every objects when no longer used or there are exceptions that I have to handle? What am I missing?
  2. Are there free tools to look up for memory leaks?
like image 561
Procule Avatar asked Nov 13 '09 21:11

Procule


2 Answers

Yeah, the garbage collector is freeing your objects when they're not used anymore.

What we usually call a memory leak in .NET is more like:

  • You're using external resources (that are not garbage collected) and forgetting to free them. This is solved usually by implementing the IDisposable interface.
  • You think there aren't references to a given object but indeed there are, somewhere and you're not using them any more but the garbage collector does not know about them.

In addition, memory is only reclaimed when needed, meaning the garbage collector activates at given times and performs a collection determining them what memory can be freed and freeing it. Until it does, the memory isn't claimed so it might look like memory is being lost.

Here, I think I'll provide a more complex answer just to clarify.

First, the garbage collector runs in its own thread. You have to understand that, in order do reclaim memory the garbage collector needs to stop all other threads so that he can follow up the reference chain an determine what depends on what. That's the reason memory isn't freed right away, a garbage collector imply certain costs in performance.

Internally the garbage collector manage memory in generations. In a very simplified way there are several generations for long lived, short lived and big size objects. The garbage collector moves the object from one generation to another each time its performs a collection which happens more often for short lived generation that for long lived one. It also reallocates objects to get you the most possible contiguous space so again, performing a collection is a costly process.

If you really want to see the effects of you freeing the form (when getting out of scope and having no more reference to it) you can call GC.Collect(). Do that just for testing, it's highly unwise to call Collect except for a very few cases where you know exactly what you're doing and the implications it will have.

A little more explaining about the Dispose method of the IDispose interface.

Dispose isn't a destructor in the usual C++ way, it isn't a destructor at all. Dispose is a way to deterministically get rid of unmanaged objects. An example: Suppose you call an external COM library that happens to allocate 1GB of memory due to what it is doing. If you have no Dispose that memory will sit there, wasting space until the GC inits a collection and reclaims the unmanaged memory by calling the actual object destructor. So if you want to free the memory right away you have to call the Dispose method but you're not "forced" to do so.

If you don't use IDisposable interface then you have to free you're unmanaged resources in the Finalize method. Finalize is automatically called from the object destructor when the GC attempts to reclaim the object. So if you have a proper finalize method the unmanaged memory will get freed either way. Calling Dispose will only make it deterministic.

like image 139
Jorge Córdoba Avatar answered Oct 01 '22 16:10

Jorge Córdoba


What leads you to conclude that there are memory leaks? Under garbage collection, there is no guarantee that memory is freed immediately, and in general the GC doesn't kick in until your process memory reaches some threshold, or the available heap has been exhausted. (The exact heuristic is complicated and not important.) So the fact that your process's memory goes up and doesn't go down doesn't necessarily mean that there's a bug. It might just be that the GC didn't get around to cleaning up your process yet.

Additionally, are you sure that there are no references to your objects? It's possible that you have references that you aren't aware of. Most memory leaks in .NET applications are because people don't realize that their memory is still being referenced somewhere.

like image 28
JSBձոգչ Avatar answered Oct 01 '22 16:10

JSBձոգչ