Need to follow these points
- StringBuilder
instead of String concatenation
- LINQ
– ‘Where’ with ‘First’ instead of FirstOrDefault
- Casting
by means of ‘(T)’ instead of ‘as (T)’ when possibly not castable
- Incorrect
exceptions re-throwing
- Not
using ‘using’ for objects disposal
- Using ‘foreach’ instead of ‘for’ for anything else than collections
1. StringBuilder instead of String concatenation
String concatenation: Add something to a string, a new address in the memory is being allocated. The previous string is copied to a new location with the newly added part. This is inefficient.
· On the other hand we have StringBuilder
which keeps the same position in the memory without performing the copy
operation, StringBuilder process is much more efficient, especially in case of
hundreds of append operations.
//INCORRECT
List values = new List(){"This
","is ","Sparta ","!"};
string outputValue = string.Empty;
foreach (var value in values)
{
outputValue += value;
}
//CORRECT
StringBuilder outputValueBuilder = new StringBuilder();
foreach (var value in values)
{
outputValueBuilder.Append(value);
}
2. LINQ – FirstOrDefault
instead of ‘Where’ with ‘First’
· If “First” is used when no value is
found, an exception will be thrown.
· Thus, it’s better to use FirstOrDefault
instead.
· When using FirstOrDefault, if no value
has been found, the default value for this type will be
returned and no exception
will be thrown.
//INCORRECT
List numbers = new List(){1,4,5,9,11,15,20,21,25,34,55};
return numbers.Where(x
=> Fibonacci.IsInFibonacciSequence(x)).First();
//PARTLY CORRECT
return numbers.First(x
=> Fibonacci.IsInFibonacciSequence(x));
//CORRECT
return numbers.FirstOrDefault(x
=> Fibonacci.IsInFibonacciSequence(x));
3. Casting
by means of ‘as (T)’ instead of ‘(T)’ when possibly not castable
· It’s common that software developers use
simple ‘(T)’ casting, instead of ‘as (T)’.
· And usually it doesn’t have any negative
influence because casted objects are
always castable. Yet,
always castable. Yet,
if there
is even a very slight probability that an object can be under some
circumstances not castable, „as (T)” casting should be used.
//INCORRECT
var woman = (Woman)person;
|
|
//CORRECT
var woman = person as Woman;
|
4. Incorrect exceptions re-throwing
· C# programmers usually forget that when
they throw an exception using„
”throw ex” they loose the stack trace. It is then considerably harder to debug an
application and to achieve appropriate log messages.
”throw ex” they loose the stack trace. It is then considerably harder to debug an
application and to achieve appropriate log messages.
· When simply using„ ”throw”
no data is lost and the whole exception together with the
stack trace can be easily retrieved.
//INCORRECT
try
{
//some code
that can throw exception [...]
}
catch (Exception
ex)
{
//some
exception logic [...]
throw ex;
}
//CORRECT
try
{
//some code
that can throw exception [...]
}
catch (Exception
ex)
{
//some
exception logic [...]
throw;
}
5. Not
using ‘using’ for objects disposal
· Many C# software developers
don’t even know that ‘using’ keyword is not only used as a directive for adding
namespaces, but also for disposing objects.
· If you know that a certain object
should be disposed after performing some operations, always use the ‘using’
statement to make sure that the object will actually be disposed.
//the below code:
using(SomeDisposableClass
someDisposableObject = new SomeDisposableClass())
{
someDisposableObject.DoTheJob();
}
//does the same as:
SomeDisposableClass
someDisposableObject = new SomeDisposableClass();
try
{
someDisposableObject.DoTheJob();
}
finally
{
someDisposableObject.Dispose();
}
6. Using
‘for’ instead of ‘foreach’ for anything else than collections
Remember that if you want
to iterate through anything that is not a collection (so through e.g. an array),
using the ‘for’ loop is much more efficient than using
the ‘foreach’ loop.
7. 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.
8 .Foreach(C#)
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.
Optimize Loops
Examine the code in loop to find the opportunities to optimize
it.
Some of them are as mentioned below:
Some of them are as mentioned below:
i. Move
out any code that does not change inside the loop. Use StringBuilder for
concatenating the strings inside the loop.
ii. Considering
inlining the code instead of calling the function which contain small amount of
code. Avoid calling properties inside a loop.
9. 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 an 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/catch block outside the for loop.
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.
//INCORRECT
Catch(Exception e)
{
}
Explicitly name the
exception to avoid catching & re-throwing. Below code catches
all System.IO exceptions:
//CORRECT
Catch(System.IO)
{
}
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.
//INCORRECT
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.
//CORRECT
Static bool
nameExists(String name)
{
If(cr.read(name)
== 0)
{
Return
false;
}
}
10. Threading
Thread Start:
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.
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();
….
}
Thread
Pool
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);
Thread
Pool 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 elapsed 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
(producing) 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.
11. 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
Weak Reference Objects
Consider
using Weak Reference when working with cached data, So that cached objects can
be resurrected (bring back to life) when needed or released by garbage
collector when there is memory pressure. Weak Reference is suitable for medium
to large sized objects stored in collection. e.g. of Weak Reference implementation
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 ArrayLists.
§ You can
measure your assembly for box & unbox instruction by using below
command line
No comments:
Post a Comment