.Net Coding performance

##[GC Basic]

In a managed process there are two types of heaps—native and managed. Native heaps are allocated with the VirtualAlloc Windows API and used by the operating system and CLR for unmanaged memory such as that for the Windows API, OS data structures, and even much of the CLR. The CLR allocates all managed .NET objects on the managed heap, also called the GC heap, because the objects on it are subject to garbage collection.

If it will not fit in an existing spot, then the allocator will expand the current boundaries of gen 0 to accommodate the new object. If this pushes past the end of the segment, it may trigger a garbage collection.

When a garbage collection occurs, a compaction may occur, in which case the GC physically moves the objects to a new location to free space in the segment.

Compaction may occur in the collection of any generation and this is a relatively expensive process because the GC must fix up all of the references to those objects so they point to the new location, which may require pausing all managed threads.

This means that if you allocate a tree of a million objects, as long as you cut off that root reference before the next GC, those million objects contribute nothing to the amount of time the GC takes.

Workstation GC: all GCs happen on the same thread that triggered the collection and run at the same priority.
Server GC creates a dedicated thread for each logical processor or core. These threads run at highest priority (THREAD_PRIORITY_HIGHEST).
If your app is running on a multi-processor machine dedicated to just your application, then the choice is clear: server GC.

Yes, this means if you use server GC and background GC, you will have two threads per processor dedicated to GC.It is not a big deal for processes to have many threads, especially when most of them are doing nothing most of the time.
If you are using workstation GC, then background GC is always enabled.

Reasons may trigger full GC: compact the fragmentations.
Class , Struct , Lazy
– 1. reference pass as parameter is fast ,but will stay on heap , need GC take care.
– 2. need lazy ?
– 3. obj small enough , consider b a struct

IMPORTANT : Collect objects in gen 0 or not at all. Objects live very briefly or forever.

In general, you should not allocate objects until right before you need them.keep lifetime as short as possible.

If your code spreads out operations on an object, try to reduce the time between the first and last uses so that the GC can collect the object as early as possible.

!!!Sometimes you will need to explicitly null out a reference to an object if it is a field on a longlived object.

IMPORTANT : Objects that have many references to other objects will take more time for the garbage collector to traverse.

You want to avoid allocations on the large object heap as much as possible.

avoid boxing if possible.


Consider (Dont)User Weak Reference For Caching . first question is ,why not use NOSQL directly?

Never implement a finalizer unless it is required. if your class implements a finalizer, you are guaranteeing that it will stay in memory even after the collection that should have killed it. This decreases overall GC efficiency and ensures that your program will dedicate CPU resources to cleaning up your object.
See http://www.writinghighperf.net/go/15 for more information about the Dispose Pattern and finalization.

casting from parent to child more expensive than casting from child to parent; from class to interface is more expensive than from interface to class.

reduce P/invoke calls if possible .which will cause memory pinned , Marshalling and unsafe .

Exception is expensive to throw.accessing the StackTrace property on an Exception object can be very expensive as it reconstructs the stack from pointers and translates it into readable text.

DLR, use dynamic only when needed . which will go through the whole CallSites flow while JIT.

IMPORTANT , Preprocessing wherever possible .

[APM (Async Programming Model)]

parallelism only when needed. Each processor can execute only a single thread at a time. When it comes time to schedule a thread for a processor, Windows needs to do a context switch.generally, thread context switch is expensive. suggest use TPL ,executing multiple Tasks on the same thread sequentially before returning the thread back to the pool.

It is often more efficient for the I/O thread to just do the quick continuation work and avoid the extra scheduling.

!!! It is never a good idea to force-terminate a thread.

ensure that your program never wastes one resource while waiting for another.

make sure that any interactions with the network, the file system, databases, or any other high-latency service is done asynchronously.

The smaller your buffers, the more overhead you will have. The larger your buffers, the longer you may need to wait for results to start coming in.

While waiting for I/O to complete, do as much other work as possible.

IMPORTANT : there is a huge difference between true asynchronous I/O and performing synchronous I/O on another thread.

You should almost never wait on Tasks.

Do Not Change Thread Priorities

thread synchronization preference :
1. No synchronization at all
2. Simple Interlocked methods
3. lock/Monitor class
4. Asynchronous locks (see later in this chapter)
5. Everything else

You should prefer to use Lazy<T> rather than implement your own pattern.

Consider Concurrent Collections only when nessacery (Bag,Dictionary,Queue,Stack). because every single access to the collection involves synchronization.

lock a batch action over lock included in a loop.

Copy resource for each thread if possible. try avoid locking if possible.

[JIT Basic]

The first time a managed method is called from your assembly, it actually runs a stub that executes the Just-in-Time (JIT) compiler which will convert the IL for that method to the hardware’s assembly instructions.

In most cases, a method will only need to be JITted once. when the method has generic type arguments. In this case, the JIT may be called for each invocation with a different
type parameter.

One of the biggest classes of optimizations is method inlining. All of these things prevent inlining:
– Virtual methods.
– Interfaces with diverse implementations in a single call site. See Chapter 5 for a
discussion of the interface dispatch problem.
– Loops.
– Exception handling.
– Recursion.
– Method bodies larger than 32 bytes of IL.

be careful the usage may cause generated code :
– The dynamic keyword
– Regular expressions
– Code generation

Author: lanliang


Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s