5 out of 16 rated this helpful - Rate this topic

Performance (C# Programming Guide)

This section covers two issues that can adversely effect performance, and links to resources on performance issues.

Boxing and Unboxing

Boxing and unboxing are computationally expensive processes. When a value type is boxed, an entirely new object must be created. This can take up to 20 times longer than an assignment. When unboxing, the casting process can take four times as long as an assignment. For more information, see Boxing and Unboxing.

Destructors

Empty destructors should not be used. When a class contains a destructor, an entry is created in the Finalize queue. When the destructor is called, the garbage collector is invoked to process the queue. If the destructor is empty, this simply results in a loss of performance. For more information, see Destructors.

Other Resources

See Also

Did you find this helpful?
(1500 characters remaining)
Community Content Add
Annotations FAQ
Avoid spuriously creating new threads
Creating a new thread is an operation more expensive than using threads in the long run.
Threads should not be created and thrown right away after a short asynchronous operation, use the thread pool if information about and control of a thread is not necessary and it may be delayed until the completion of other tasks assigned to the thread pool.
  • 11/8/2007
  • Kea
Use value types instead of reference types

If you have a commonly created class, and doesn't inherit from anything, and nothing derives from it (possibly sealed), then you should turn it into a struct.

However; if it is to be passed often as a parameter, and is larger than 16 bytes, then you should consider leaving it as a class, as the benefits will be lost due to the "copy by value" nature of value types.

The reason for this is that structs are lightweight; they don't have a sync block index, and are created on the stack, so no garbage collection is neccessary to free them.

 

There are, however, exceptions to this guide, of course. For example, if you have an object that is created in large numbers, but are bigger than 16 bytes, it may still be a good idea to create them as structures if you intend to send them to methods. This is what the ref/out keywords are for.

Keep expressions simple

This one may be obvious, but keep your lines of maths code short. This makes it easier for the compiler and the JITter to optimise the code down into simple, RISC-like instructions.

As opposed to:

Y= A*X^2 + B*X + (X/3)^X

Try to calculate each term on a seperate line.

For example, the above could be converted into the following:

Y = A*X*X;
Y += B*X;
Y += (X/3)^X;
Arrange logical expressions for early termination

Because expressions such as (a && b && c) or (a || b || c) are converted to individual statements, it is wise to arrange the operands in order based on how likely they are to evaluate true. This is because the compiler short-curcuits the expressions; that is, if someone evaluates to be true in an OR expression, the rest of the operands will not be tested, and if something evaluates false in an AND expression, the rest of the operands will not be evaluated.

Let's say that b is true pretty much always, a is true about half the time, and c is rarely true. For the first statement, you would arrange them this way:

(c && a && b)

This is because if c is false, then there is no need to test a or b.

For the OR statement, you should arrange it this way:

(b || a || c)

Because b will probably be true, a and c don't need to be evaluated.

This brings up why your evaluations should not have side effects; they may or may not happen, depending on the ordering of the statement.

Advertisement