Tuesday, July 24, 2012

GC, Memory, and Multi-Threading in C#

GL to me, my 50th post and is the 1st technical post.
if ur a senior programmer u might be bored and r welcomed to comment.

lets start.
i have something to do around, say, 60 times. (usually 5000 time, *10 sec is 14 hrs)
linear, like for, takes say 60 * 10 sec =  10 mins.
but if i multi thread it, say 10 at a time in a good cpu i can get to 20 sec or less for all 10 threads, so where done to 2 min (or almost 4 hrs) - cool!
so in a basic way to do that would be that : http://bresleveloper.blogspot.co.il/2012/05/muti-threading-in-forforeach-example.html

now u should thing hey - says who that after all these threads are finished all this CPU usage and memory gets free? msdn says so : "For the majority of the objects that your application creates, you can rely on the .NET Framework's garbage collector to implicitly perform all the necessary memory management tasks. However, when you create objects that encapsulate unmanaged resources, you must explicitly release the unmanaged resources when you are finished using them in your application. "

so rule 1: if we dont use unmanaged code we dont need to worry about our memory. or better to say memory leak.

so when will i call the GC? according to msdn : "In almost all cases, you do not have to call this method, because the garbage collector runs continuously. This method is primarily used for unique situations and testing."

so rule 2: we do not call the GC
if ur really hot on using GC then google about "when to use GC C#"
if it solves you problem then either ur really 1 of the special cases (probably not) or you missed something down here.

so basicly calling thread and / or function that only use managed code, i.e. .Net classes and structs that do not implement IDISPOSABLE that we can be at ease that memory is managed well.

when do i need to start thinking?
in our basic case - i the thread gets an exception. for an infinite loop case u can put a timeout. but if the thread gets and exception it will probably get stuck and "eat" ur memory.
at the begining i tried to check each thread and NULL it and its container (List<>).

but that was wrong.
the good solution is a good OOP design where ur thread is wrapped in a T/C (try catch) so that if any exceptions occur it will end, and if it ends it gets collected
if you cant do that that Thread.Abort() would do it, and it will be collected the moment u leave the method or the moment you clear ur container, as long as there is no other place refering (pointing) it.

so to finalize that part - in managed multi threading make sure all ur thread gets finished safely, best with T/C wrap.

and when i use unmanaged code?
the very basic is that every managed class implement IDisposable, so call the Dispose() method (and /or Close() if needed, if its there u usualy need it).
Best practice is to use the using(){} wrapper wherever u can (yes, even if its "stupid" having 15+ using)
when having a class using unmanaged give it the IDSIPOSABLE and implement it calling the Dispose() of everything, same in methods, same in threads.
in classes its also good to use Destructors, usually u can just call Dispose() there.

conclusion: if u implement everywhere Dispose() and "freeing" all the references ur program should be fine.

if u still find urself with ur machine choking then here is a check list
1 - did i lose ALL the references everywhere?
2 - did i close ALL my streams/connection/anything with Close method?
3 - did i disposed every resource when not using it anymore, i.e. calling Dispose on everything that have dispose when i finished using it?
4 - are all my threads gets finished properly and safely?

*global instances are the dangerous part here, and it will be (harder work but) better to put every instance in its main/top method and pass it to all the submethods or create more classes for those cases.

if all these are checked than either u missed something (sry) or find ur Ex or comment me when u find the problem.
also a few interesting point:
- the part of the memory that gets "stuck" is the part that belong to Resources
- therefor the GC might keep all kind of ref-types to it
- usually the system will get slow becuz of the Resources becoming heavy and GC.Collect wont help
- basicly a well written class has a finalizer that is being called when the c# class no longer holds references so unless u use something u wrote, with classes that MS wrote u should be fine even without calling dispose (o.c. not recommended)

and to the one of most interest and i quote:
"Dispose() immediately releases the resources associated with your object. Yes, GC is non-deterministic, but calling Dispose() does not trigger a GC!"
so it ease the entire OS but does not release ur app personal memory.
from here:
http://stackoverflow.com/questions/7520881/is-it-bad-practice-to-depend-on-the-net-automated-garbage-collector

an excellent and simple article to understand the .NET GC and destrucors:
http://www.c-sharpcorner.com/uploadfile/chandrahundigam/understandingdestructors11192005021208am/understandingdestructors.aspx
another good summery:
http://stackoverflow.com/questions/4267729/what-happens-if-i-dont-call-dispose-on-the-pen-object/5555243#5555243

No comments:

Post a Comment