Common .NET Memory Issues
Charl
Botha, senior developer at Intervate, and I had some discussions around .NET
memory issues, and how to measure the size of a CLR object in memory.
Here's what
Charl had to say:
"I have yet
to discover how one can retrieve the size of an object in pure CLR, the method
that I used was to take an object created in CLR, get the GCHandle, then get
the size of the object in unmanaged memory. This I don't think would help you.
There is
software available that you can use, free, that can measure memory usage.
They are
dead slow since they are virtual machines, like Java, but are able to take the
measurements for you.
The CLR
profiler I found to be the best product to help me find out which objects are
not memory happy.
Here's a list
of things that are not very good to memory and will abuse you system.
Note, this
infromation was composed nearly two years ago based on the 1.1 .Net framework,
so I'm not 100% sure that they still affect the system as badly as they did
last time.
1. Delegates,
the typical += assigning to events, a lot of coders abuse this and every time a
new object is created they create a new delegate and bind it to the object,
bad.
There
should only be one delegate created when the assembly is loaded and reused, the
-= must then be used to unbind the object when the destructor is called or
disposed. Very, very important.
2. Secondly,
fonts, brushes, and graphics in general. Each graphically driven object needs a
handle, and handles are created when the object is created. But when the GC
collects the object, it does not dispose of the handle, bad.
Once again,
use the object that are already created by the application and not manually by
your code.
3. Streams,
any stream reader or writer must be closed and disposed, if a coder does not do
this, the handle to the memory is kept open until the process is killed.
Always, close stream, so search through your code and see where you open
streams, from files, to XML, to serialization.
4. Threads,
every time a thread is created in the virtual machine, certain memory is
allocated to control this thread, in the real world, i.e. OS systems 5+
allocate 1mb of memory to manage a thread, create a lot of threads, use a lot
of memory, whenever possible use thread managers and processing queues to run
transactions rather than just creating a thread for every transaction.
5. Lastly,
use the GC.WaitForPendingFinalizers after transactions, this will help with
thread memory allocation not just application memory, remember, threads drive
process, processes, drive jobs."
Hope this
discussion helps others, as it helped me with some commonly encountered .NET
memory usage and development issues.