Introduction
This articles aims to help and inform on how to improve code performance.
Background
The reason this article is being made comes from the help it was given me here at code project to improve some code I was doing.
I intend to summarize the ideas based on other articles and if you wish to learn more about them, the reference will be at the end.
Just because you can get more done with less effort is not a license to abdicate your responsibility to code wisely.
- Design for efficient resource management:
Quite simple, avoid allocating objects and their resources before you actually need them and make sure they will be released as soon as they are not being used.
- Reduce boundary crossing:
Try to reduce the number of method calls that cross remoting boundaries because this introduces marshaling
and potentially thread switching overhead
- Prefer Single Large Assemblies over many small ones:
If you have many small assemblies loading together, check to see if it is possible to turn them into one. This might reduce over heading on loading metadata, security checks and more.
- Treat threads as a Shared Resource:
Creating threads is an expensive operation and may affect scalability. Whenever possible, try to treat them as a shared resource and use the optimized .NET thread pool.
- Do not make classes threads safe by default:
Thread control is usually needed at a higher layer in the software architecture rather than individual class level and the incorrect use may cause unnecessary overhead from thread-safety features. Also, thread safe collections have a more complex design to offer those thread-safety services.
- Consider using a sealed key word:
Sealing methods makes them candidates for inlining and other compiling optimizations. Just a note, always consider all implication of sealing a method or class.
public class MainClass
{
protected virtual void Method()
{
}
}
You can override and seal the method in a derived class.
public class DerivedClass : MainClass
{
protected override sealed void Method()
{
}
}
- Consider the Tradeoff of virtual members:
If you don't need to extend your class, then try to avoid virtual members due to their more expensive calls that can negate certain run-time performance optimizations.
- Consider using overloaded methods:
Sensitive methods that takes any number of parameters result in code paths for each possible combination of parameters. If it is possible,
change it by a small set of overloaded methods.
void DoSomething (params object [] parameters)
void DoSomething (int aParameters, int otherParameters)
void DoSomething (int aParameters, int otherParameters, int otherOtherParameter)
- Know the cost of accessing a property:
Properties that simply get or set a variable without any extra logic perform like a public variable. The following table shows the time needed (in ns) to get and set integer instance fields and properties
AVG | MIN | PRIMITIVE |
1.0 | 1.0 | Get Field |
1.2 | 1.2 | Set Field |
1.2 | 1.2 | Get/Set Property |
6.4 | 6.3 | Get/Set virtual Field/Property |
Source: http://msdn.microsoft.com/en-us/library/ms973852.aspx
- Private vs Public members:
Public member cause additional overhead when you use the XmlSerializer
class.
- Avoid Calling GC.Collect:
Whenever you call the GC.Collect
method, it will execute the full collection of all group object generations. This is a very expensive operation because all objects must be visited to ensure a complete collection. The garbage collector is designed to be self-tuning and it adjusts its operation as required, but if there is a reason that makes calling it necessary, consider doing the following:
System.GC.Collect();
System.GC.WaitForPendingFinalizers();
System.GC.Collect();
- Prefer Arrays to Collections:
Arrays are the fastest of all collections, so unless you need special functionality, such as dynamic extension of the collection, you should consider using arrays rather than collections. Arrays also avoid the boxing and unboxing overhead.
- Consider FOR instead of FOREACH:
Use for instead of foreach, in C#, to iterate the contents of arrays or collections in performance critical code, it will avoid unecessary overhead, specially if you do not need the protections offered by foreach.
- Review your code:
Prioritize your code review process by identifying code paths that are frequently executed and begin your review process in these areas. 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.
- Use String builder:
StringBuilder is efficient for string concatenation where the number and size of appends is unknown.
StringBuilder example;
example.Append(str1);
example.Append(str2);
example.Append(str3);
example.Append(str4);
sb.Append(str1+str2+str3+str4);
- Avoid Rethrowing 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.
- Know how to deal with data access
There are a series of key things which must be considered:
- Ensure you close your connections properly to reduce resource pressure.
- Make sure that your code uses the correct data provider.
- When a stored procedure doesn't return a value, use "ExecuteNonQuery" for optimum performance.
- When accessing wide rows or rows with BLOB data, consider the use of "CommandBehavior.SequentialAccess" with "GetBytes" to access BLOB in chunks.
- Returning large amounts of data increases query time and the time it takes to transfer the data across the network
- Boxing and Unboxing Overhead:
The act of boxing causes both a operations of heap allocation and a memory copy. Avoid passing value types in method parameters that expect a reference type. Where boxing is unavoidable, 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.
int num = 123;
object boxedNum;
box = (object)num;
Source
MSDN Library for all hyperlinks and http://msdn.microsoft.com/pt-br/library/ms998547.aspx
for the description and definitions that I summarized here. I reccomend the reading for everyone. It is far more detailed and contains way more examples.