Hi Steph.
I would like to give another perspective on GC's and how they work.
Memory-management comes in three flawors; direct and explicit,
reference-counted and implicit; and garbage collected.
- Direct explicit de-allocation:
This is typically for pointer driven langs like c and pascal, not to mention
asm. It's fast but dangerous. What ever memory you allocate you must free
yourself. This is also why C++ and Delphi-code gets bloated with a lot of
try/finally clauses. If you forget to free an object you got a leak.
pros: fast!
cons: very tedious and very error-prone.
- Reference-counted implicit
This is a technique used in COM, and by so, this is stuff you may use in
Delphi and C++, but is mandatory in VB. For COM the IUnknown interface
sports the AddRef and Release methods. VB-code gets injected with calls to
all COM-objects AddRef method on assignment or when sent as parameters. And
when a sub or function goes out of scope it calls Release on those
interfaces. AddRef just increases a counter while Release does a simple if
myrefcount = 0 then killme.
pros: makes for easy coding
cons: hurts performance. COM and VB is not known for it's high speed. =)
Also, ref-count cannot handle circular references (AddRef's) and it's still
possible to create memory leaks by creating islands of object-groups.
- Garbage collection
Now a GC is another beast. It manages the entire heap and does so by keeping
track of all 'roots'. Every application has one root, the rest of them are
the current references on the stack. The GC can kick in at any time but
typically does so when it's first generation gets full (gen0).
When the GC kicks in, it will make a pretty cynical and dreadful assumption:
- All Objects Are Dead!
Then it will loop from it's first root and make an object graph of all
objects that can be reached.
The ones that cannot be reached are now very much dead. Note how this solves
the circular reference problem described above. All objects that can be
reached will be moved to gen1 of the GC. Later, if gen1 gets full it will
collect to gen2.
The generations are currently at gen0 of 256KiB, a gen1 of 2MiB and a gen2
of 16MiB. gen2 can increase in size, but when before it tries to allocate
more space, it tries to move objects back to gen0 and gen1 a few times and
hope most of them get killed. It's a rather nifty system.
pros: makes for easy coding
cons: not predictable. You never know when it will start its run and when
done. Can't work with real-time data.
But, as objects may use 'external' resources like open files on disk,
database connections and some GUI controls, we need IDispose to make sure to
free those resources, as it can take forever before the GC frees your
object. milliseconds, seconds, days, months... You just don't know.
Anyways, few objects needs this kinda cleansing. FxCop can tell you if you
forgot to call Dispose() on a object and this will come as a vanilla-feature
in future versions of Visual Studio (While I think it should have been there
from day one).
A 'good' .NET developer knows that some objects needs Disposing, a 'great'
C# dev does this with the using-statement. A 'awesome' dev doesn't forget to
run FxCop before the release to find the places he forgot and/or can ignore.
=)
Happy Allocating
- Michael S
I have an Object " MyEmploye " :
Class MyEmploye
{
private string Name;
private string Surname;
}
Instances of this object are referenced by instances of an ArrayList
"MyArrayList" . One instance of MyArrayList is referenced by the "Tag"'
property of each Item of a ListView "MyListView".
"Reference" tree is :
- ListView
- ListViewItems
- Tag
- MyArrayList
- MyEmploye
My question is :
When I call "MyListView.Dispose();" does the GC free the memory
allocated for the all the instances of "MyEmploye" objects ?
Any help will be appreciated,
Thanks,
Steph.