CutHimSomeSlack
CutHimSomeSlack

Reputation: 193

If GC does its job why do we get Out of Memory Exceptions?

Usually I am told that GC is pretty smarter than all of us and don't mess with it, so I am thinking when memory is low it goes and frees up memory for the program. Well then why I sometimes still get out of memory exceptions on large objects?

Currently again I am coming close to another scenario that might run out of memory. I have a class level dictionary of list of some classes, it has like 200,000 keys. I had to keep it at a global level so somewhere in one of my methods I needed it, but as soon as I am done with it in that method I want to free up its space. Is setting it to null enough?

private void Foo()
{
   // do stuff with MY_DICTIONARY
   MY_DICTIONARY = null  // ?
   // whew! freeded up memory or not?
}

Upvotes: 2

Views: 178

Answers (8)

Larry
Larry

Reputation: 18051

Emptying your dictionary is not enough. Are your classes implementing IDisposable ?

If yes, then you also must call Dispose() at some time on an object when you dont need it anymore, before to remove it from the dictionary so the unmanaged resources they uses internally are freed. Unmanaged resources may include memory usage that needs to be freed this way.

I had the same issue with an important amount of Images in a collection. I ended up with a Out of memory exception, because I did not called Dispose() before removing it from the collection.

What is true with my picture objects are also for every objects that implements IDisposable.

If you own the code of the classes in your dictionary, have a look on this question which explains how to implement IDisposable in details.

Upvotes: 0

Perfect28
Perfect28

Reputation: 11327

It's not enough if you've kept a reference of it somewhere on your code :

// somewhere away 
COPY_DICTIONARY = MY_DICTIONARY ;

.....

MY_DICTIONARY = null ; 
// Won't free the inial dictionary because COPY_DICTIONARY keep referencing the object

Upvotes: 1

Matthew Haugen
Matthew Haugen

Reputation: 13286

The GC is nondeterministic as to when it will get called, exactly. It is not an immediate matter that memory is freed the instance that it's no longer used, it happens when the computer is open enough to do it. In many cases, this can be sooner rather than later, but there's still no guarantee that it will happen immediately.

That's why methods like GC.Collect() exist. In most cases we don't have to worry, because we're dealing with small enough variables and enough RAM that "eventually" is more than sufficient for our uses. The garbage collector is offered as a utility, not a deity. It's useful, because it works in almost every case (particularly in applications cases). And in most cases, we don't have to worry about storing all that much data (if we do in applications, we might want to review our design to implement some paging to not display as much at once in the first place). But just because we're using managed memory is no promise that it will be managed in a solid, 100% way and that we can throw anything at them.

That's one of the reasons languages like C++ still exist. As you said, the GC is very smart, and very good at its job. So it's nice not to have to think about malloc and free and just to rest some trust on that, but that doesn't mean it can read our minds.

It's kind of like cruise control. You can drive down the road and set cruise control to maintain a constant speed, but when you start to climb a hill, it will take a moment to catch up and start increasing your throttle to maintain the speed. Similarly, it will let you fall down the hill more quickly than you might have otherwise. The GC is aware of what objects are free-able in memory, but it is not necessarily aware of the details of the context, and the idea is that it acts passively behind our code. Otherwise, it would cause some severe performance issues.

As many other people have also noted, and I think is important in a more practical sense, the GC will, of course, only collect resources that are no longer in use or scope. Thus, if the elements in your Dictionary are used elsewhere (and are passed by references, i.e. are classs), they will not be collected. Furthermore, if you keep your Dictionary as a static member, it will never be collected.

Upvotes: 3

AFract
AFract

Reputation: 9700

You could get Out of memory exceptions even if with a lot of free RAM, especially if you use huge lists of object like in your case : please have a look for "Large Object Heap fragmentation" to see how this kind of structures are handled in memory.

To avoid these errors, you could use other structures to handle huge collections (are smallest chunks of lists), and use a memory profiler on your code to detect where the failures occurs.

Upvotes: 1

dyson
dyson

Reputation: 896

You will get out of memory exceptions where there are enough instances of objects in scope to fill it up. If you create an infinite loop, creating an object within each one, you'll run out of memory eventually; the garbage collector cannot get rid of the objects you are creating, as there is still code that can access them.

Upvotes: 1

Douglas
Douglas

Reputation: 37781

Yes, that will do. Any object which is still referenced will not be treated as garbage, so the garbage collection will not free the memory for that object. Since it is possible to reference lots of objects with lots of data, and the GC only frees unreferenced objects, it is still possible to get Out of Memory exceptions.

Upvotes: 1

James Curran
James Curran

Reputation: 103605

That would free up the Dictionary. However, it would only free the items held in the dictionary if there is nothing else holding a reference to any of them.

Upvotes: 1

Steven Wood
Steven Wood

Reputation: 2785

As far as I know the GC only cleans up resources that arenot needed any more. if you have a RAM capacity of 128Mb and you create a byte array of length 128 000 000 but are still using it then all available memory will be filled regardless of the GC, however when the method declaring that array is finished the GC will clean it up and free the resources. (assuming that the out of memory exception was not thrown)

Upvotes: 1

Related Questions