Wednesday, August 5, 2015

C#.NET Performance Guidelines

String Operations:-
Review your code which performs intensive stringmanipulations.
‘+’ Operator:-
When number of operands is known, perform stringconcatenate using +operator.
e.g.

String str = “abc” + “xyz” + “pqr”
Why -
StringBuilder Class:-
When number of operand is unknown, perform string concatenate using StringBuilder.Append(). Such as string concatenation in loop , you should use StringBuilder
e.g.

for(int i=0; i<Results.count; i++)
{
         StringBuilder.Append(Results[i])
}
Some example to demonstrate StringBuilder:

//prefer this
StringBuilder sb;
Sb.Append(str1);
Sb.Append(str2);

//Over this
Sb.Append(str1+str2);

//prefer this for concatenate string for various functions
Void F1(sb, …);
Void F2(sb, …);

//Over this
StringBuilder sb;
Sb.Append(F1(…));
Sb.Append(F2(…));
String.Compare():-
When performing case-insensitive string comparisons, Check for the lines which calls ToLower() as these are not required for performing case-insensitive comparisons

String.Compare(String str1, String str2, bool ignoreCase);
Calling ToLower() method & then comparing will require temporary string allocation which can be expensive when called in Loop
Looping & Recursions:-
Slight inefficiency in looping & recursions is magnified due to it being repeatedly called.
Recursions
·         In some scenarios looping is preferable than using recursion because recursive call builds new stack frame for calls which results in memory consumption
·         Looping does not require building stack frame unless a method is called inside a loop
·         Make sure the recursive call have a way out & there is no danger of running out of stack space
Foreach(C#):-
Foreach provides an enumerator by overrriding IEnumerable.GetEnumerator. This causes to add both managed heap & virtual function overhead on simple types
Use for loop instead of foreach to iterate through simple type array OR collection (built in value types such as int, char etc..) in performance critical code.
Properties:-
Though properties looks like a field it has hidden costs. You should design the classes accordingly to define properties & fields as required
You need to be-aware that when the property is accessed, additional code such as validation check can be executed. Hence this might be slower than accessing a field. Simple properties like setting or getting the private member variable there is no performance difference as compared to accessing a field. However if you use virtual properties it become easily complicated as virtual properties cannot be in-lined
Repeatedly accessing a property in for loop becomes more expensive. So if possibly it should be read outside the for loop
Optimize Loops:-
Examine the code in loop to find the opportunities to optimize it. Some of them are as mentioned below
·         Move out any code that does not change inside the loop
·         Use StringBuilder for concatenating the strings inside the loop
·         Considering inlining the code instead of calling the function which contain small amount of code
·         If you test multiple condition inside the loop, begin the expression which will most likely allow you to exit
·         Avoid calling properties inside a loop.
Exception Handling:-
Exception handling by try/catch block is recommended way to handle exceptional error condition in managed code. Improper managed exceptions can significantly affect performance



Finally block:-
Make sure you use finally block to free up your resources. Finally block is always executed, even if an exception occurs
e.g.:

try
{
  conn.Open(); // assume some connection object, which implements IDisposable
}
finally
{
 if(null!=conn)
   conn.Close();  // Always executed even if an exception occurs
}
Else you can use using construct in C#, which call the dispose at end of the construct, assuming the required resource implements the Idisposable

Using(conn)
{
 conn.open();
}
Rethrow exception:-
The cost of using throw to rethrow a existing exception is same a throwing the new exception.

Try{
//do something which can throw an exception
}
Catch(Exception e){
Throw;
}
In above e.g. there is no saving from re-throwing the existing exception. You should consider wrapping an re-throwing the exception on when it provides additional diagnostic information.
Loops:-
Check if your code throws an exception inside for loop. This should be avoided, place your try/catchblock outside the forloop.
Reduce unnecessary exception:-
Do not catch exception which you cannot handle. You should catch exception to provide some debugging information (exception details) or retry any failed information.
Avoid catching generic exception, this leads to catching all exception & most of these exceptions are re-thrown eventually.

Catch(Exception e)
{
}
Explicitly name the exception to avoid catching & re-throwing. Below code catches all System.IOexceptions:

Catch(System.IO)
{
}
Preserve as much as diagnostic information as possible in your exception handlers
Avoid exception to control application flow:-
Do not use exception to control your application flow. If you except events in normal course of code execution, you should not throw an exception. In below e.g. exception is thrown inappropriately when customer name is not found

Static void nameExists(String name)
{
If(cr.read(name) == 0)
{
Throw(new Exception(“name not found”));
}
}
Name not found is expected condition, so re-factor the code to return value instead of throwing exception

Static bool nameExists(String name)
{
         If(cr.read(name) == 0)
         {
                 Return false;
}
}
Locking & Synchronization:-
Mutex object
Tradeoff for mutex object is when you require interprocess synchronization. Do not use mutex to cross –synchronization of threads within a single process. Mutex object is more expensive as this is kernel object, hence provides cross-process synchronization
Lock”this”
For correctness reasons avoid locking on this object. Instead provide a private object to lock on. Below is example

//prefer this
Class A{
Private Object mylock = new Object();
Lock(myLock)
{  …  }
}

//over this
Class A{
Lock(this)
{    …   }
}
“This” is external visible object & you never know what other code might be acquiring this same lock
If you require a atomic updates to your member variable use System.Threading.Interlocked class

Lock typeof(object)
Avoid locking type of the object, because there might be other threads in same process that lock on same type of object. Hence it might cause your code to hang until the thread releases the lock on same type of object
This also creates a potential to create deadlocks. Prefer using a private static object in your class to provide synchronization

//prefer this
Class A{
Private static Object _lock = new object();
Lock(_lock)
{   ….   }
}

//over this
Lock(typeof(myObject))
ReaderWriterLock
Tradeoff for using ReaderWriterLock is when you require multiple threads to read the resource concurrently & synchronized access to write the resource. Hence during such scenarios ReaderWriter lock should be preferred over Lock & Monitor locking mechanisms
Threading:-
ThreadStart
Indiscriminately spawning the threads can easily reduce your application performance rather than improving. Frequently creating new threads can lead to extensive context switching, memory allocation & additional cleanup when a thread dies
Recycling threads with thread pools results in superior quality, then spawning new thread for new requests
Below code shows new thread been created & maintained for each page load

Private void page_load(Object o, System.EventArgs e){
If (page.isPastBack)
{
         ThreadStart ts = new ThreadStart(callFunc);
         Thread tr = new Thread(ts);
         Tr.start();
         ….
}
ThreadPool
Use CLR thread pool to execute thread based work, to avoid expensive thread creation OR initialization. Below code shows method been executed using a thread from thread pool

WaitCallBack methodTarget = new WaitCallBack(MyClass.updateCache)
ThreadPool.QueueUserWorkItem(methodTarget);
ThreadPool class uses a thread from application pool to execute the method passed in callback as soon a thread is available
System.Threading.Timer
Use Timer class to perform periodic tasks. Timer class provides execution of method by specifying the time interval. Each time the timer elasped a thread from a thread pool is used to execute the method indicated in TimerCallBack.
Below code shows calling the myFunc() method every 30 secs

TimerCallBack myCallBack = new TimerCallBack(myFunc);
Timer tr = new System.Threading.Timer(myCallBack, null, 0, 30000,);
Static void myFunc(object state)
{
         …..
}
This results in optimal performance because it avoids thread initialization incurred in spawning new thread
Thread.Abort
Aviod using Thread.Abort for terminating other threads. Abort caused CLR to throw a ThreadAbortException on a thread to be terminated. You can use Thread.Join to wait on the thread to make sure that the thread has terminated
Thread.Resume / Thread.suspend
Never call Thread.Resume OR Thread.suspend to synchronize the activities between the threads. Never call suspend to suspend low priority thread, instead consider setting Thread.Priority property
Calling suspend on one thread from other can cause application deadlock. For example you might suspend a thread holding May resources needed by other threads
If you want to synchronize activities between multiple threads try using synchronization objects like lock, mutex, monitor, Events etc..
Memory Management:-
Call Dispose OR Close
Your code should call Dispose or Close on all objects which supports this methods. For e.g. all the objects which implements Idisposable
Common disposable objects are as follows:
·         Database – Connection, DataReader & Transaction
·         File – FileStream, BinaryWriter
·         Stream Based – StreamReader/Writer, TextReader/Writer, BinaryReader/Writer
Also, check Finally & Using blocks to ensure resources are released
Complex Object Graphs
Candidates for the complex object graph can be those with many references to other objects. Complex Object graphs can result in additional work for garbage collectors to create & allocate these objects. Identify opportunities to simplify the structures & classes to have good heap locality & easier to maintain
Also, identify the problem where short-lived objects are referenced from long-lived objects. As a result of this short-lived object are been promoted from generation 0 & increases burden on garbage collector
WeakReference Objects:-
Consider using WeakReference when working with cached data, So that cached objects can be resurrected when needed or released by garbage collector when there is memory pressure. WeakReference is suitable for medium to large sized objects stored in collection
e.g. of WeakReferenceimplementation is as below:

Void someMethod()
{
         ArrayList arList = new ArrayList[5];
         MyObject obj = new MyObject();
         WeakReference wr = new WeakReference(obj);
         arList.add(wr);
         //retrive Weak reference
         WeakReference wr = (WeakReference)arList[0];
         //Create new myObj to be assigned
         MyObject myObj = Null;
         If(Weakreference.IsAlive)
                 myObj = (MyObject)wr.Target;       //if this object is not collected
                                                    //by garbage collector
         if(MyObj == NULL)
{
         //As object is collected by GC, surrect again
}
}
GC.Collect:-
Garbage collector is self tuning, by programmatically forcing a collection you might hinder the performance rather than improve. Your code should not call GC.Collect explicitly
Finalizers:-
Use finalization for the objects that need to perform cleanup task during collection process & just before the object memory is reclaimed. Finalizers are mainly use to release unmanaged resources (database connection, file handles, COM object reference) maintained by object
Use below consideration for writing Finalizers
·         Implement finalizer only for the object which holds unmanaged code. Unnecessary finalizers adds extra load to finalizer thread as well as garbage collector
·         Class that implements finalizers should also implements Idisposable and the dispose function should use supressFinalization if the cleanup is already been performed in dispose function
·         Dispose methods should call dispose of base class as well as dispose of class members
·         Cleanup code in Finalizers should be thread safe for thread safe types
Boxing & Unboxing:-
Boxing & unboxing enables value types to be treated as objects (reference). Boxing a value type packages it inside an instance of type Object reference type. This results in storing value type in managed heap. Unboxing is reversed process which extracts value from the object type
Consider below example

Int I = 111;
Object o = (Object) I;    //boxing – allocated value type on managed heap by
                          //creating new object
O = 222;
I = (int)o; //unboxing
Boxing & unboxing are computationally expensive process i.e. when a value type is boxed entirely new object has to be created & allocated
Some considerations:
·         Avoid passing value types to the method which expect a reference type
·         Pay attention to code in loops where boxing overhead can quickly add up
·         Consider using arrays or collection of custom-type class rather than using collection of System.Objects. For example consider arrays to store integer value type instead of using ArrayList
·         You can measure your assembly for box & unbox instruction by using below command line
Ildasm.exe yourcomponent.dll /text | findstr box (OR unbox)


No comments:

Post a Comment