Wednesday 20 November 2013

Common Performance Issues in .net



Common Performance Issues
During your code reviews, pay particular attention to the following areas:
  • Frequent code paths. Prioritize your code review process by identifying code paths that are frequently executed and begin your review process in these areas.
  • Frequent loops. Even the slightest inefficiency inside a loop is magnified many times over depending on the number of iterations. Specifically watch out for repetitive property access inside your loops, using foreach instead of for, performing expensive operations within your loops, and using recursion. Recursion incurs the overhead of having to repeatedly build new stack frames.
There are a few areas that regularly lead to performance bottlenecks. Start your code review by looking for the following common performance issues:
  • Resource cleanup
  • Exceptions
  • String management
  • Threading
  • Boxing
Resource Cleanup
Failing to clean up resources is a common cause of performance and scalability bottlenecks. Review your code to make sure all resources are closed and released as soon as possible. This is particularly important for shared and limited resources such as connections. Make sure your code calls Dispose (or Close) on disposable resources. Make sure your code uses finally blocks or using statements to ensure resources are closed even in the event of an exception.
Exceptions
While structured exception handling is encouraged because it leads to more robust code and code that is less complex to maintain than code that uses method return codes to handle error conditions, exceptions can be expensive.
Make sure you do not use exception handling to control regular application flow. Use it only for exceptional conditions. Avoid exception handling inside loops surround the loop with a try/catch block instead if that is required. Also identify code that swallows exceptions or inefficient code that catches, wraps, and rethrows exceptions for no valid reason.
String Management
Excessive string concatenation results in many unnecessary allocations, creating extra work for the garbage collector. Use StringBuilder for complex string manipulations and when you need to concatenate strings multiple times. If you know the number of appends and concatenate strings in a single statement or operation, prefer the + operator. In ASP.NET applications, consider emitting HTML output by using multiple Response.Write calls instead of using a StringBuilder.
Threading
Server-side code should generally use the common language runtime (CLR) thread pool and should not create threads on a per-request basis. Review your code to ensure that appropriate use is made of the thread pool and that the appropriate synchronization primitives are used. Make sure your code does not lock whole classes or whole methods when locking a few lines of code might be appropriate. Also make sure your code does not terminate or pause threads by using Thread.Abort or Thread.Suspend.
Boxing
Boxing causes a heap allocation and a memory copy operation. Review your code to identify areas where implicit boxing occurs. Pay particular attention to code inside loops where the boxing overhead quickly adds up. Avoid passing value types in method parameters that expect a reference type. Sometimes this is unavoidable. In this case, to reduce the boxing overhead, box your variable once and keep an object reference to the boxed copy as long as needed, and then unbox it when you need a value type again.
Excessive boxing often occurs where you use collections that store System.Object types. Consider using an array or a custom-typed collection class instead.
To identify locations that might have boxing overhead, you can search your assembly's Microsoft intermediate language (MSIL) code for the box and unbox instructions, using the following command line.
Ildasm.exe yourcomponent.dll /text | findstr box
Ildasm.exe yourcomponent.dll /text | findstr unbox
To measure the overhead, use a profiler.
Managed Code and CLR Performance
While the .NET CLR is designed for high performance, the way in which you write managed code can either take advantage of that high performance or hinder it. Use the review questions in this section to analyze your entire managed source code base. The review questions apply regardless of the type of assembly. This section helps you identify coding techniques that produce inefficient managed code, which in turn can lead to performance problems. For more information about the issues raised in this section, see Chapter 5, "Improving Managed Code Performance." This section describes the following:
  • Memory management
  • Looping and recursion
  • String operations
  • Exception handling
  • Arrays
  • Collections
  • Locking and synchronization
  • Threading
  • Asynchronous processing
  • Serialization
  • Visual Basic considerations
  • Reflection and late binding
  • Code access security
  • Ngen.exe
Memory Management
Use the following review questions to assess how efficiently your code uses memory:
  • Do you manage memory efficiently?
  • Do you call GC.Collect?
  • Do you use finalizers?
  • Do you use unmanaged resources across calls?
  • Do you use buffers for I/O operations?
Do You Manage Memory Efficiently?
To identify how efficiently your code manages memory, review the following questions:
  • Do you call Dispose or Close?
Check that your code calls Dispose or Close on all classes that support these methods. Common disposable resources include the following:
    • Database-related classes: Connection, DataReader, and Transaction.
    • File-based classes: FileStream and BinaryWriter.
    • Stream-based classes: StreamReader, TextReader, TextWriter, BinaryReader, and TextWriter.
    • Network-based classes: Socket, UdpClient, and TcpClient.
Also check that your C# code uses the using statement to ensure that Dispose is called. If you have Visual Basic .NET code, make sure it uses a Finally block to ensure that resources are released.
  • Do you have complex object graphs?
Analyze your class and structure design and identify those that contain many references to other objects. These result in complex object graphs at runtime, which can be expensive to allocate and create additional work for the garbage collector. Identify opportunities to simplify these structures. Simpler graphs have superior heap locality and they are easier to maintain.
Another common problem to look out for is referencing short-lived objects from long-lived objects. Doing so increases the likelihood of short-lived objects being promoted from generation 0, which increases the burden on the garbage collector. This often happens when you allocate a new object and then assign it to a class level object reference.
  • Do you set member variables to null before long-running calls?
Identify potentially long-running method calls. Check that you set any class-level member variables that you do not require after the call to null before making the call. This enables those objects to be garbage collected while the call is executing.
Note   There is no need to explicitly set local variables to null because the just-in-time (JIT) compiler can statically determine that the variable is no longer referenced.
  • Do you cache data using WeakReference objects?
Look at where your code caches objects to see if there is an opportunity to use weak references. Weak references are suitable for medium- to large-sized objects stored in a collection. They are not appropriate for very small objects.
By using weak references, cached objects can be resurrected easily if needed or they can be released by garbage collection when there is memory pressure.
Using weak references is just one way of implementing caching policy. For more information about caching, see "Caching" in Chapter 3, "Design Guidelines for Application Performance."
  • Do you call ReleaseComObject?
If you create and destroy COM objects on a per-request basis under load, consider calling ReleaseComObject. Calling ReleaseComObject releases references to the underlying COM object more quickly than if you rely on finalization. For example, if you call COM components from ASP.NET, consider calling ReleaseComObject. If you call COM components hosted in COM+ from managed code, consider calling ReleaseComObject. If you are calling a serviced component that wraps a COM component, you should implement Dispose in your serviced component, and your Dispose method should call ReleaseComObject. The caller code should call your serviced component's Dispose method.
Do You Call GC.Collect?
Check that your code does not call GC.Collect explicitly. The garbage collector is self-tuning. By programmatically forcing a collection with this method, the chances are you hinder rather than improve performance.
The garbage collector gains its efficiency by adopting a lazy approach to collection and delaying garbage collection until it is needed.
Do You Use Finalizers?
Finalization has an impact on performance. Objects that need finalization must necessarily survive at least one more garbage collection than they otherwise would; therefore, they tend to get promoted to older generations.
As a design consideration, you should wrap unmanaged resources in a separate class and implement a finalizer on this class. This class should not reference any managed object. For example, if you have a class that references managed and unmanaged resources, wrap the unmanaged resources in a separate class with a finalizer and make that class a member of the outer class. The outer class should not have a finalizer.
Identify which of your classes implement finalizers and consider the following questions:
  • Does your class need a finalizer?
Only implement a finalizer for objects that hold unmanaged resources across calls. Avoid implementing a finalizer on classes that do not require it because it adds load to the finalizer thread as well as the garbage collector.
  • Does your class implement IDisposable?
Check that any class that provides a finalizer also implements IDisposable, using the Dispose pattern described in Chapter 5, "Improving Managed Code Performance."
  • Does your Dispose implementation suppress finalization?
Check that your Dispose method calls GC.SuppressFinalization. GC.SuppressFinalization instructs the runtime to not call Finalize on your object because the cleanup has already been performed.
  • Can your Dispose method be safely called multiple times?
Check that clients can call Dispose multiple times without causing exceptions. Check that your code throws an ObjectDisposedException exception from methods (other than Dispose) if they are invoked after calling Dispose.
  • Does your Dispose method call base class Dispose methods?
If your class inherits from a disposable class, make sure that it calls the base class's Dispose.
  • Does your Dispose method call Dispose on class members?
If you have any member variables that are disposable objects, they too should be disposed.
  • Is your finalizer code simple?
Check that your finalizer code simply releases resources and does not perform more complex operations. Anything else adds overhead to the dedicated finalizer thread which can result in blocking.
  • Is your cleanup code thread safe?
For your thread safe types, make sure that your cleanup code is also thread safe. You need to do this to synchronize your cleanup code in the case where multiple client threads call Dispose at the same time.
Do You Use Unmanaged Resources Across Calls?
Check that any class that uses an unmanaged resource, such as a database connection across method calls, implements the IDisposable interface. If the semantics of the object are such that a Close method is more logical than a Dispose method, provide a Close method in addition to Dispose.
Do You Use Buffers for I/O Operations?
If your code performs I/O or long-running calls that require pinned memory, investigate where in your code the buffers are allocated. You can help reduce heap fragmentation by allocating them when your application starts. This increases the likelihood that they end up together in generation 2, where the cost of the pin is largely eliminated. You should also consider reusing and pooling the buffers for efficiency.
Looping and Recursion
Inefficient looping and recursion can create many bottlenecks. Also, any slight inefficiency is magnified due to it being repeatedly executed. For this reason, you should take extra care to ensure the code within the loop or the recursive method is optimized. For more information about the questions and issues raised in this section, see "Iterating and Looping" in Chapter 5, "Improving Managed Code Performance." Use the following review questions to help identify performance issues in your loops:
  • Do you repetitively access properties?
  • Do you use recursion?
  • Do you use foreach?
  • Do you perform expensive operations within your loops?
Do You Repetitively Access Properties?
Repeated accessing of object properties can be expensive. Properties can appear to be simple, but might in fact involve expensive processing operations.
Do You Use Recursion?
If your code uses recursion, consider using a loop instead. A loop is preferable in some scenarios because each recursive call builds a new stack frame for the call. This results in consumption of memory, which can be expensive depending upon the number of recursions. A loop does not require any stack frame creation unless there is a method call inside the loop.
If you do use recursion, check that your code establishes a maximum number of times it can recurse, and ensure there is always a way out of the recursion and that there is no danger of running out of stack space.
Do You Use foreach?
Using foreach can result in extra overhead because of the way enumeration is implemented in .NET Framework collections. .NET Framework 1.1 collections provide an enumerator for the foreach statement to use by overriding the IEnumerable.GetEnumerator. This approach is suboptimal because it introduces both managed heap and virtual function overhead associated with foreach on simple collection types. This can be a significant factor in performance-sensitive regions of your application. If you are developing a custom collection for your custom type, consider the following guidelines while implementing IEnumerable:
  • If you implement IEnumerable.GetEnumerator, also implement a nonvirtual GetEnumerator method. Your class's IEnumerable.GetEnumerator method should call this nonvirtual method, which should return a nested public enumerator struct.
  • Explicitly implement the IEnumerator.Current property on your enumerator struct.
For more information about implementing custom collections and about how to implement IEnumerable as efficiently as possible, see "Collection Guidelines" in Chapter 5, "Improving Managed Code Performance."
Consider using a for loop instead of foreach to increase performance for iterating through .NET Framework collections that can be indexed with an integer.
Do You Perform Expensive Operations Within Your Loops?
Examine the code in your loop and look for the following opportunities for optimization:
  • Move any code out of the loop that does not change in the loop.
  • Investigate the methods called inside the loop. If the called methods contain small amounts of code, consider inlining them or parts of them.
  • If the code in the loop performs string concatenation, make sure that it uses StringBuilder.
  • If you test for multiple exit conditions, begin the expression with the one most likely to allow you to exit.
  • Do not use exceptions as a tool to exit one or more loops.
  • Avoid calling properties within loops and if you can, check what the property accessor does. Calling a property can be a very expensive operation if the property is performing complex operations.
String Operations
Review your code to see how it performs string manipulation. Intensive string manipulation can significantly degrade performance. Consider the following questions when reviewing your code's string manipulation:
  • Do you concatenate strings?
  • Do you use StringBuilder?
  • Do you perform string comparisons?
Do You Concatenate Strings?
If you concatenate strings where the number of appends is known, you should use the + operator as follows.
String str = "abc" + "def" + "ghi";
If the number and size of appends is unknown, such as string concatenation in a loop, you should use the StringBuilder class as follows.
for (int i=0; i< Results.Count; i++){
  StringBuilder.Append (Results[i]);
}
Do You Use StringBuilder?
StringBuilder is efficient for string concatenation where the number and size of appends is unknown. Some of the scenarios which demonstrate an efficient way of using StringBuilder are as follows:
  • String concatenation
·         //Prefer this
·         StringBuilder sb;
·         sb.Append(str1);
·         sb.Append(str2);
·          
·         //over this
·         sb.Append(str1+str2);
  • Concatenating strings from various functions
·         //Prefer this
·         void f1( sb,);
·         void f2( sb,);
·         void f3( sb,);
·          
·         //over this
·         StringBuilder sb;
·         sb.Append(f1());
·         sb.Append(f2());
·         sb.Append(f3());
Do You Perform String Comparisons?
Check whether your code performs case-insensitive string comparisons. If it does, check that it uses the following overloaded Compare method.
String.Compare (string strA, string strB, bool ignoreCase);
Watch out for code that calls the ToLower method. Converting strings to lowercase and then comparing them involves temporary string allocations. This can be very expensive, especially when comparing strings inside a loop.
More Information
For more information about the issues raised in this section, see "String Operations" in Chapter 5, "Improving Managed Code Performance."
Exception Handling
Managed code should use exception handling for robustness, security, and to ease maintenance. Used improperly, exception management can significantly affect performance. For more information about the questions and issues raised in this section, see "Exception Management" in Chapter 5, "Improving Managed Code Performance." Use the following review questions to help ensure that your code uses exception handling efficiently:
  • Do you catch exceptions you cannot handle?
  • Do you control application logic with exception handling?
  • Do you use finally blocks to ensure resources are freed?
  • Do you use exception handling inside loops?
  • Do you re-throw exceptions?
Do You Catch Exceptions You Cannot Handle?
You should catch exceptions for very specific reasons, because catching generally involves rethrowing an exception to the code that calls you. Rethrowing an exception is as expensive as throwing a new exception.
Check that when your code catches an exception, it does so for a reason. For example, it might log exception details, attempt to retry a failed operation, or wrap the exception in a new exception and throw the outer exception back to the caller. This operation should be performed carefully and should not obscure error details.
Do You Control Application Logic with Exception Handling?
Check that your code does not use exception handling to control the flow of your normal application logic. Make sure that your code uses exceptions for only exceptional and unexpected conditions. If you throw an exception with the expectation that something other than a general purpose handler is going to do anything with it, you have probably done something wrong. You can consider using bool return values if you need to specify the status (success or failure) of a particular activity.
For example, you can return false instead of throwing an exception if a user account was not found in the database. This is not a condition that warrants an exception. Failing to connect to the database, however, warrants an exception.
Do You Use Finally Blocks to Ensure Resources Are Freed?
Make sure that resources are closed after use by using try/catch blocks. The finally block is always executed, even if an exception occurs, as shown in the following example.
SqlConnection conn = new SqlConnection(connString);
try
{
  conn.Open();  // Open the resource
}
finally
{
 if(null!=conn)
   conn.Close();  // Always executed even if an exception occurs
}
Note   C# provides the using construct that ensures an acquired resource is disposed at the end of the construct. The acquired resource must implement System.IDisposable or a type that can be implicitly converted to System.IDisposable, as shown in the following example.
Font MyFont3 = new Font("Arial", 10.0f);
using (MyFont3)
{
    // use MyFont3
}   // compiler will generate code to call Dispose on MyFont3
Do You Use Exception Handling Inside Loops?
Check if your code uses exceptions inside loops. This should be avoided. If you need to catch an exception, place the try/catch block outside the loop for better performance.
Do You Rethrow Exceptions?
Rethrowing exceptions is inefficient. Not only do you pay the cost for the original exception, but you also pay the cost for the exception that you rethrow.
Rethrowing exceptions also makes it harder to debug your code because you cannot see the original location of the thrown exception in the debugger. A common technique is to wrap the original exception as an inner exception. However, if you then rethrow, you need to decide whether the additional information from the inner exception is better than the superior debugging you would get if you had done nothing.
Arrays
Arrays provide basic functionality for grouping types. To ensure that your use of arrays is efficient, review the following questions:
  • Do you use strongly typed arrays?
  • Do you use multidimensional arrays?
Do You Use Strongly Typed Arrays?
Identify places in your code where you use object arrays (arrays containing the Object type). If you use object arrays to store other types, such as integers or floats, the values are boxed when you add them to the array. Use a strongly typed array instead, to avoid the boxing. For example, use the following to store integers.
int[] arrIn = new int[10];
Use the preceding to store integers instead of the following.
Object[] arrObj = new Object[10];
Do You Use Multidimensional Arrays?
If your code uses multidimensional arrays, see if you can replace the code with a jagged array (a single dimensional array of arrays) to benefit from MSIL performance optimizations.
Note   Jagged arrays are not CLS compliant and may not be used across languages. For more information, see "Use Jagged Arrays Instead of Multidimensional Arrays" in Chapter 5, "Improving Managed Code Performance."
Collections
To avoid creating bottlenecks and introducing inefficiencies, you need to use the appropriate collection type based on factors such as the amount of data you store, whether you need to frequently resize the collection, and the way in which you retrieve items from the collection.
For design considerations, see Chapter 4, "Architecture and Design Review of a .NET Application for Performance and Scalability." Chapter 4 addresses the following questions:
  • Are you using the right collection type?
  • Have you analyzed the requirements?
  • Are you creating your own data structures unnecessarily?
  • Are you implementing custom collections?
For more information see "Collection Guidelines" in Chapter 5, "Improving Managed Code Performance." Chapter 5 asks the following questions:
  • Do you need to sort your collection?
  • Do you need to search your collection?
  • Do you need to access each element by index?
  • Do you need a custom collection?
Review the following questions if your code uses arrays or one of the .NET Framework collection classes:
  • Have you considered arrays?
  • Do you enumerate through collections?
  • Do you initialize the collection to an approximate final size?
  • Do you store value types in a collection?
  • Have you considered strongly typed collections?
  • Do you use ArrayList?
  • Do you use Hashtable?
  • Do you use SortedList?
Have You Considered Arrays?
Arrays avoid boxing and unboxing overhead for value types, as long as you use strongly typed arrays. You should consider using arrays for collections where possible unless you need special features such as sorting or storing the values as key/value pairs.
Do You Enumerate Through Collections?
Enumerating through a collection using foreach is costly in comparison to iterating using a simple index. You should avoid foreach for iteration in performance-critical code paths, and use for loops instead.
Do You Initialize the Collection to an Approximate Final Size?
It is more efficient to initialize collections to a final approximate size even if the collection is capable of growing dynamically. For example, you can initialize an ArrayList using the following overloaded constructor.
ArrayList ar = new ArrayList (43);
Do You Store Value Types in a Collection?
Storing value types in a collection involves a boxing and unboxing overhead. The overhead can be significant when iterating through a large collection for inserting or retrieving the value types. Consider using arrays or developing a custom, strongly typed collection for this purpose.
Note   At the time of this writing, the .NET Framework 2.0 (code-named "Whidbey") introduces generics to the C# language that avoid the boxing and unboxing overhead.
Have You Considered Strongly Typed Collections?
Does your code use an ArrayList for storing string types? You should prefer StringCollection over ArrayList when storing strings. This avoids casting overhead that occurs when you insert or retrieve items and also ensures that type checking occurs. You can develop a custom collection for your own data type. For example, you could create a Cart collection to store objects of type CartItem.
Do You Use ArrayList?
If your code uses ArrayList, review the following questions:
  • Do you store strongly typed data in ArrayLists?
Use ArrayList to store custom object types, particularly when the data changes frequently and you perform frequent insert and delete operations. By doing so, you avoid the boxing overhead. The following code fragment demonstrates the boxing issue.
ArrayList al = new ArrayList();
al.Add(42.0F); // Implicit boxing because the Add method takes an object
float f = (float)al[0]; // Item is unboxed here
  • Do you use Contains to search ArrayLists?
Store presorted data and use ArrayList.BinarySearch for efficient searches. Sorting and linear searches using Contains are inefficient. This is of particular significance for large lists. If you only have a few items in the list, the overhead is insignificant. If you need several lookups, then consider Hashtable instead of ArrayList.
Do You Use Hashtable?
If your code uses a Hashtable collection of key/value pairs, consider the following review questions:
  • Do you store small amounts of data in a Hashtable?
If you store small amounts of data (10 or fewer items), this is likely to be slower than using a ListDictionary. If you do not know the number of items to be stored, use a HybridDictionary.
  • Do you store strings?
Prefer StringDictionary instead of Hashtable for storing strings, because this preserves the string type and avoids the cost of up-casting and down-casting during storing and retrieval.
Do You Use SortedList?
You should use a SortedList to store key-and-value pairs that are sorted by the keys and accessed by key and by index. New items are inserted in sorted order, so the SortedList is well suited for retrieving stored ranges.
You should use SortedList if you need frequent re-sorting of data after small inserts or updates. If you need to perform a number of additions or updates and then re-sort the whole collection, an ArrayList performs better than the SortedList.
Evaluate both collection types by conducting small tests and measuring the overall overhead in terms of time taken for sorting, and choose the one which is right for your scenario.
Locking and Synchronization
To help assess the efficiency of your locking and synchronization code, use the following questions:
  • Do you use Mutex objects?
  • Do you use the Synchronized attribute?
  • Do you lock "this"?
  • Do you lock the type of an object?
  • Do you use ReaderWriterLocks?
Do You Use Mutex Objects?
Review your code and make sure that Mutex objects are used only for cross-process synchronization and not cross-thread synchronization in a single process. The Mutex object is significantly more expensive to use than a critical section with the Lock (C#) or SyncLock (VB) statement.
Do You Use the Synchronized Attribute?
See which of your methods are annotated with the synchronized attribute. This attribute is coarse-grained and it serializes access to the entire method such that only one thread can execute the method at any given instance, with all threads waiting in a queue. Unless you specifically need to synchronize an entire method, use an appropriate synchronization statement (such as a lock statement) to apply granular synchronization around the specific lines of code that need it. This helps to reduce contention and improve performance.
Do You Lock "this"?
Avoid locking "this" in your class for correctness reasons, not for any specific performance gain. To avoid this problem, provide a private object to lock on.
public class A {
    lock(this) { }
  }
// Change to the code below:
public class A
{
  private Object thisLock = new Object();
    lock(thisLock) { }
  }
Use this approach to safely synchronize only relevant lines of code. If you require atomic updates to a member variable, use System.Threading.Interlocked.
Do You Lock The Type of an Object?
Avoid locking the type of the object, as shown in the following code sample.
lock(typeof(MyClass));
If there are other threads within the same process that lock on the type of the object, this might cause your code to hang until the thread locking the type of the object is finished executing.
This also creates a potential for deadlocks. For example, there might be some other application in a different application domain in the same process that acquires a lock on the same type and never releases it.
Consider providing a static object in your class instead, and use that as a means of synchronization.
private static Object _lock = new Object();
lock(_lock);
For more information, see "A Special Dr. GUI: Don't Lock Type Objects!" on MSDN at http://msdn.microsoft.com/en-us/library/aa302312.aspx.
Do You Use ReaderWriterLock?
Check whether your code uses ReaderWriterLock objects to synchronize multiple reads and occasional writes. You should prefer the ReaderWriterLock over the other locking mechanisms such as lock and Monitor, where you need to occasionally update data which is read frequently, such as a custom cache collection. The ReaderWriterLock allows multiple threads to read a resource concurrently but requires a thread to wait for an exclusive lock to write the resource.
For more information, see "ReaderWriterLock Class" in the .NET Framework Class Library on MSDN at http://msdn.microsoft.com/en-us/library/system.threading.readerwriterlock(VS.71).aspx.
More Information
For more information about the questions and issues raised in this section, see "Locking and Synchronization" and "Locking and Synchronization Guidelines" in Chapter 5, "Improving Managed Code Performance."
To review your approach to locking and synchronization from a design perspective, see "Concurrency" in Chapter 4, "Architecture and Design Review for .NET Application Performance and Scalability."
Threading
If you misuse threads, you can easily reduce your application's performance rather than improve it. Review your code by using the following questions to help identify potential performance-related issues caused by misuse of threads or inappropriate threading techniques. For more information about the questions and issues raised in this section, see "Threading Guidelines" in Chapter 5, "Improving Managed Code Performance."
  • Do you create additional threads?
  • Do you call Thread.Suspend or Thread.Resume?
  • Do you use volatile fields?
  • Do you execute periodic tasks?
Do You Create Additional Threads?
You should generally avoid creating threads, particularly in server-side code use the CLR thread pool instead. In addition to the cost of creating the underlying operating system thread, frequently creating new threads can also lead to excessive context switching, memory allocation, and additional cleanup when the thread dies. Recycling threads within the thread pool generally leads to superior results.
Do You Call Thread.Suspend or Thread.Resume?
Use synchronization objects if you need to synchronize threads. Calling Thread.Suspend and Thread.Resume to synchronize the activities of multiple threads can cause deadlocks. Generally, Suspend and Resume should be used only in the context of debugging or profiling, and not at all for typical applications. Use synchronization objects such as ManualResetEvent objects if you need to synchronize threads.
Do You Use Volatile Fields?
Limit the use of the volatile keyword because volatile fields restrict the way the compiler reads and writes the contents of the fields. Volatile fields are not meant for ensuring thread safety.
Do You Execute Periodic Tasks?
If you require a single thread for periodic tasks, it is cheaper to have just one thread explicitly executing the periodic tasks and then sleeping until it needs to perform the task again. However, if you require multiple threads to execute periodic tasks for each new request, you should use the thread pool.
Use the Threading.Timer class to periodically schedule tasks. The Timer class uses the CLR thread pool to execute the code.
Note that a dedicated thread is more likely to get scheduled at the correct time than a pooled thread. This is because if all threads are busy, there could be a delay between the scheduled time of the background work and a worker thread becoming available. If there is a dedicated thread for the background work, a thread will be ready at the appointed time.
Asynchronous Processing
You can use asynchronous calls to help increase application concurrency.
To ensure that you use asynchronous processing appropriately, review the following questions:
  • Do you poll for asynchronous invocation resources?
  • Do you call EndInvoke after calling BeginInvoke?
Do You Poll for Asynchronous Invocation Results?
Avoid polling for asynchronous invocation results. Polling is inefficient and uses precious processor cycles which can be used by other server threads. Use a blocking call instead. Methods of AsyncResult.AsyncWaitHandle.WaitHandle class such as WaitOne, WaitAll, and WaitAny are good examples of blocking calls.
Do You Call EndInvoke After Calling BeginInvoke?
Review your code to see where it calls BeginInvoke to use asynchronous delegates. For each call to BeginInvoke, make sure your code calls EndInvoke to avoid resource leaks.
More Information
For more information about the questions and issues raised in this section, see "Asynchronous Calls Explained" and "Asynchronous Calls Guidelines" in Chapter 5, "Improving Managed Code Performance."
To review your design and how it uses asynchronous processing see "Concurrency" in Chapter 4, "Architecture and Design Review of a .NET Application for Performance and Scalability."
Serialization
Inefficient serialization code is a common performance-related problem area. To review whether your code uses serialization, search for the "Serializable" string. Classes that support serialization should be decorated with the SerializableAttribute; they may also implement ISerializable. If your code does use serialization, review the following questions:
  • Do you serialize too much data?
  • Do you serialize DataSet objects?
  • Do you implement ISerializable?
Do You Serialize Too Much Data?
Review which data members from an object your code serializes. Identify items that do not need to be serialized, such as items that can be easily recalculated when the object is deserialized. For example, there is no need to serialize an Age property in addition to a DateOfBirth property because the Age can easily be recalculated without requiring significant processor power. Such members can be marked with the NonSerialized attribute if you use the SoapFormatter or the BinaryFormatter or the XmlIgnore attribute if you use the XmlSerializer class, which Web services use.
Also identify opportunities to use structures within your classes to encapsulate the data that needs to be serialized. Collecting the logical data in a data structure can help reduce round trips and lessen the serialization impact.
Do You Serialize DataSet Objects?
The DataSet object generates a large amount of serialization data and is expensive to serialize and deserialize. If your code serializes DataSet objects, make sure to conduct performance testing to analyze whether it is creating a bottleneck in your application. If it is, consider alternatives such as using custom classes.
Do You Implement ISerializable?
If your classes implement ISerializable to control the serialization process, be aware that you are responsible for maintaining your own serialization code. If you implement ISerializable simply to restrict specific fields from being serialized, consider using the Serializable and NonSerialized attributes instead. By using these attributes, you will automatically gain the benefit of any serialization improvements in future versions of the .NET Framework.
More Information
For more information about improving serialization performance and DataSet serialization, see "How To: Improve Serialization Performance" in the "How To" section of this guide.
For more information about the various options for passing data across the tiers of a distributed .NET application, see Chapter 4, "Architecture and Design Review of a .NET Application for Performance and Scalability."
Visual Basic Considerations
When optimized, Visual Basic .NET code can perform as well as C# code. If you have ported existing Visual Basic code to Visual Basic .NET, performance is unlikely to be optimized because you are unlikely to be using the best .NET coding techniques. If you have Visual Basic .NET source code, review the following questions:
  • Have you switched off int checking?
  • Do you use on error goto?
  • Do you turn on Option Strict and Explicit?
  • Do you perform lots of string concatenation?
Have You Switched Off int Checking?
Int checking is beneficial during development, but you should consider turning it off to gain performance in production. Visual Basic turns on int checking by default, to make sure that overflow and divide-by-zero conditions generate exceptions.
Do You Use On Error Goto?
Review your code to see if it uses the on error goto construct. If it does, you should change your code to use the .NET structured exception handling with Try/Catch/Finally blocks. The following code uses on error goto.
Sub AddOrderOld(connstring)
    On Error GoTo endFunc
    Dim dataclass As DAOrder = New DAOrder
    Dim conn As SqlConnection = New
                      SqlConnection(connstring)
    dataclass.AddOrder(conn)
  EndFunc:
    If Not(conn is Nothing) Then
     conn.Close()
    End If
End Sub
The following code shows how this should be rewritten using exception handling.
Sub AddOrder(connstring)
   Dim conn As SqlConnection
   Try
     Dim dataclass As DAOrder = New DAOrder
     conn = New SqlConnection(connstring)
     dataclass.AddOrder(conn)
   Catch ex As Exception
     ' Exception handling code
   Finally
    If Not(conn is Nothing) Then
     conn.Close()
    End If
   End Try
End Sub
Do You Turn on Option Strict and Explicit?
Review your code and ensure that the Strict and Explicit options are turned on. This ensures that all narrowing type coercions must be explicitly specified. This protects you from inadvertent late binding and enforces a higher level of coding discipline. OptionExplicit forces you to declare a variable before using it by moving the type-inference from run time to compile time. The code for turning on Explicit and Strict is shown in the following code sample.
Option Explicit On
Option Strict On
If you compile from the command line using the Vbc.exe file, you can indicate that the compiler should turn on Strict and Explicit as follows.
vbc mySource.vb /optionexplicit+ /optionstrict+
Do You Perform Lots of String Concatenation?
If your code performs lots of string concatenations, make sure that it uses the StringBuilder class for better performance.
Note   If you use ASP.NET to emit HTML output, use multiple Response.Write calls instead of using a StringBuilder.
Reflection and Late Binding
Use the following review questions to review your code's use of reflection:
If your code uses reflection, review the following questions:
  • Do you use .NET Framework classes that use reflection?
  • Do you use late binding?
  • Do you use System.Object to access custom objects?
Do You Use .NET Framework Classes that Use Reflection?
Analyze where your code uses reflection. It should be avoided on the critical path in an application, especially in loops and recursive methods. Reflection is used by many .NET Framework classes. Some common places where reflection is used are the following:
  • The page framework in ASP.NET uses reflection to create the controls on the page, and hook event handlers. By reducing the number of controls, you enable faster page rendering.
  • Framework APIs such as Object.ToString use reflection. Although ToString is a virtual method, the base Object implementation of ToString uses reflection to return the type name of the class. Implement ToString on your custom types to avoid this.
  • The .NET Framework remoting formatters, BinaryFormatter and SOAPFormatter, use reflection. While they are fast for referenced objects, they can be slow for value types which have to be boxed and unboxed to pass through the reflection API.
Do You Use Late Binding?
In Visual Basic .NET, a variable is late bound if it is declared as an Object or is without an explicit data type. When your code accesses members on late-bound variables, type checking and member lookup occurs at run time. As a result, early-bound objects have better performance than late-bound objects. The following example shows a data class being assigned to an object.
Sub AddOrder()
    Dim dataclass As Object = New DAOrder
    ' Dim dataclass as DAOrder  = New DAOrder will improve performance
    ' Do other processing
End Sub
Do You Use System.Object to Access Custom Objects?
Avoid using System.Object to access custom objects because this incurs the performance overhead of reflection. Use this approach only in situations where you cannot determine the type of an object at design time.
More Information
For more information about the questions and issues raised in this section, see "Reflection and Late Binding" in Chapter 5, "Improving Managed Code Performance."
Code Access Security
Code access security supports the safe execution of semi-trusted code, protects users from malicious software, and prevents several kinds of attacks. It also supports the controlled, code identity-based access to resources. Use the following review questions to review your use of code access security:
  • Do you use declarative security?
  • Do you call unmanaged code?
Do You Use Declarative Security?
Where possible, it is recommended that you use declarative security instead of imperative security checks. The current implementation of demand provides better performance and support with the security tools that are currently being built to help security audits.
Note that if your security checks are conditional within a method, imperative security is your only option.
Do You Call Unmanaged Code?
When calling unmanaged code, you can remove the runtime security checks by using the SuppressUnmanagedCodeSecurity attribute. This converts the check to a LinkDemand check, which is much faster. However, you should only do so if you are absolutely certain that your code is not subject to luring attacks.
More Information
For more information about the questions and issues raised in this section, see "Code Access Security" in Chapter 5, "Improving Managed Code Performance."
For more information about the danger of luring attacks and the potential risks introduced by using SuppressUnmanagedCodeSecurity and LinkDemand, see Chapter 8, "Code Access Security in Practice" in "Improving Web Application Security: Threats and Countermeasures" on MSDN at http://msdn.microsoft.com/en-us/library/aa302424.aspx.
Class Design Considerations
Review your class design using the following questions:
  • Do you use properties?
  • Do you define only the required variables as public?
  • Do you seal your classes or methods?
Do You Use Properties?
You can expose class-level member variables by using public fields or public properties. The use of properties represents good object-oriented programming practice because it allows you to encapsulate validation and security checks and to ensure that they are executed when the property is accessed.
Properties must be simple and should not contain more code than required for getting/setting and validation of the parameters. Properties can look like inexpensive fields to clients of your class, but they may end up performing expensive operations.
Do You Define Only the Required Variables As Public?
You can scope member variables as either public or private members. Think carefully about which members should be made public because with public members you run the risk of exposing sensitive data that can easily be manipulated. In addition to security concerns, you should also avoid unnecessary public members to prevent any additional serialization overhead when you use the XmlSerializer class, which serializes all public members by default.