Pixytech

Lead Architect  •  Full Stack Engineer

Category: .Net Concepts

  • .Net Garbage collection (GC)

     In this article we are going to cover Garbage collection algorithm, Finalization (internals), Resurrection, Weak Reference (Short and long – internals), Generations, GC methods and GC 4.0 features (Background GC).

    Garbage collection in the Microsoft .NET common language runtime environment completely absolves the developer from tracking memory usage and knowing when to free memory. This article gives a detailed step-by-step description of how the garbage collection algorithm works internally.
    Every program uses resources of one sort or another “memory buffers, screen space, network connections, database resources, and so on.
    The steps required to access a resource are as follows:

    • Allocate memory for the type that represents the resource.
    • Initialize the memory to set the initial state of the resource and to make the resource usable.
    • Use the resource by accessing the instance members of the type (repeat as necessary).
    • Tear down the state of the resource to clean up.
    • Free the memory.

    This seemingly simple paradigm has been one of the major sources of programming errors.
    As I examine GC, you’ll notice that it completely absolves the developer from tracking memory usage and knowing when to free memory. However, the garbage collector doesn’t know anything about the resource represented by the type in memory. This means that a garbage collector can’t know how to perform step four “tearing down the state of a resource. To get a resource to clean up properly, the developer must write code that knows how to properly clean up a resource. In the .NET Framework, the developer writes this code in a Close, Dispose, or Finalize method, which I’ll describe later. However, as you’ll see later, the garbage collector can determine when to call this method automatically.
    Also, many types represent resources that do not require any cleanup. For example, a Rectangle resource can be completely cleaned up simply by destroying the left, right, width, and height fields maintained in the type’s memory. On the other hand, a type that represents a file resource or a network connection resource will require the execution of some explicit clean up code when the resource is to be destroyed.
     

    Resource Allocation

     
    The Microsoft® .NET common language runtime requires that all resources be allocated from the managed heap. There are several GC algorithms in use today. Each algorithm is fine-tuned for a particular environment in order to provide the best performance. This article concentrates on the GC algorithm that is used by the common language runtime.

    When a process is initialized, the runtime reserves a contiguous region of address space that initially has no storage allocated for it. This address space region is the managed heap. The heap also maintains a pointer, which I’ll call the NextObjPtr. This pointer indicates where the next object is to be allocated within the heap. Initially, the NextObjPtr is set to the base address of the reserved address space region.
    An application creates an object using the new operator. This operator first makes sure that the bytes required by the new object fit in the reserved region (committing storage if necessary). If the object fits, then NextObjPtr points to the object in the heap, this object’s constructor is called, and the new operator returns the address of the object.

     

     

     

    Figure 1 Managed Heap

     

    At this point, NextObjPtr is incremented past the object so that it points to where the next object will be placed in the heap. Figure 1 shows a managed heap consisting of three objects: A, B, and C. The next object to be allocated will be placed where NextObjPtr points (immediately after object C).
    For the managed heap, allocating an object simply means adding a value to a pointer. Here we are assuming that address space and storage are infinite.
    When an application calls the new operator to create an object, there may not be enough address space left in the region to allocate to the object. The heap detects this by adding the size of the new object to NextObjPtr. If NextObjPtr is beyond the end of the address space region, then the heap is full and a collection must be performed.
    In reality, a collection occurs when generation 0 is completely full. Briefly, a generation is a mechanism implemented by the garbage collector in order to improve performance. The idea is that newly created objects are part of a young generation, and objects created early in the application’s lifecycle are in an old generation. Separating objects into generations can allow the garbage collector to collect specific generations instead of collecting all objects in the managed heap. We will discuss the generation in detail further in this article.

     

    The Garbage Collection Algorithm

     
    The garbage collector checks to see if there are any objects in the heap that are no longer being used by the application. If such objects exist, then the memory used by these objects can be reclaimed. (If no more memory is available for the heap, then the new operator throws an OutOfMemoryException.)
    Every application has a set of roots. Roots identify storage locations, which refer to objects on the managed heap or to objects that are set to null. For example, all the global and static object pointers in an application are considered part of the application’s roots. In addition, any local variable/parameter object pointers on a thread’s stack are considered part of the application’s roots. Finally, any CPU registers containing pointers to objects in the managed heap are also considered part of the application’s roots. The list of active roots is maintained by the just-in-time (JIT) compiler and common language runtime, and is made accessible to the garbage collector’s algorithm.
    When the garbage collector starts running, it makes the assumption that all objects in the heap are garbage. In other words, it assumes that none of the application’s roots refer to any objects in the heap. Now, the garbage collector starts walking the roots and building a graph of all objects reachable from the roots. For example, the garbage collector may locate a global variable that points to an object in the heap.
    Figure 2 shows a heap with several allocated objects where the application’s roots refer directly to objects A, C, D, and F. All of these objects become part of the graph. When adding object D, the collector notices that this object refers to object H, and object H is also added to the graph. The collector continues to walk through all reachable objects recursively.

     

     

     

     

     

     

     

     

     

     

    Figure 2 Allocated Objects in Heap

     

    Once this part of the graph is complete, the garbage collector checks the next root and walks the objects again. As the garbage collector walks from object to object, if it attempts to add an object to the graph that it previously added, then the garbage collector can stop walking down that path. This serves two purposes. First, it helps performance significantly since it doesn’t walk through a set of objects more than once. Second, it prevents infinite loops should you have any circular linked lists of objects.
    Once all the roots have been checked, the garbage collector’s graph contains the set of all objects that are somehow reachable from the application’s roots; any objects that are not in the graph are not accessible by the application, and are therefore considered garbage. The garbage collector now walks through the heap linearly, looking for contiguous blocks of garbage objects (now considered free space). The garbage collector then shifts the non-garbage objects down in memory (using the standard memcpy function that you’ve known for years), removing all of the gaps in the heap. Of course, moving the objects in memory invalidates all pointers to the objects. So the garbage collector must modify the application’s roots so that the pointers point to the objects’ new locations. In addition, if any object contains a pointer to another object, the garbage collector is responsible for correcting these pointers as well. Figure 3 shows the managed heap after a collection.


     

    Figure 3 Managed Heap after Collection

     

    After all the garbage has been identified, all the non-garbage has been compacted, and all the non-garbage pointers have been fixed-up, the NextObjPtr is positioned just after the last non-garbage object. At this point, the new operation is tried again and the resource requested by the application is successfully created.
    It is not possible to leak resources, since any resource not accessible from your application’s roots can be collected at some point. Second, it is not possible to access a resource that is freed, since the resource won’t be freed if it is reachable. If it’s not reachable, then your application has no way to access it.

    Finalization

     
    The garbage collector offers an additional feature that you may want to take advantage of: finalization. Finalization allows a resource to gracefully clean up after itself when it is being collected. By using finalization, a resource representing a file or network connection is able to clean itself up properly when the garbage collector decides to free the resource’s memory.
    when the garbage collector detects that an object is garbage, the garbage collector calls the object’s Finalize method (if it exists) and then the object’s memory is reclaimed. For example, let’s say you have the following type (in C#):
    public class BaseObj {
    public BaseObj() {
    }

    protected override void Finalize() {
    // Perform resource cleanup code here…
    // Example: Close file/Close network connection
    Console.WriteLine(“In Finalize.”);
    }
    }
    Now you can create an instance of this object by calling:
    BaseObj bo = new BaseObj();

    Some time in the future, the garbage collector will determine that this object is garbage. When that happens, the garbage collector will see that the type has a Finalize method and will call the method, causing “In Finalize” to appear in the console window and reclaiming the memory block used by this object.
    When designing a type it is best to avoid using a Finalize method. There are several reasons for this:

    • Finalizable objects get promoted to older generations, which increases memory pressure and prevents the object’s memory from being collected when the garbage collector determines the object is garbage. In addition, all objects referred to directly or indirectly by this object get promoted as well. Generations and promotions will be discussed in this article below.
    • Finalizable objects take longer to allocate.
    • Forcing the garbage collector to execute a Finalize method can significantly hurt performance. Remember, each object is finalized. So if I have an array of 10,000 objects, each object must have its Finalize method called.
    • Finalizable objects may refer to other (non-finalizable) objects, prolonging their lifetime unnecessarily. In fact, you might want to consider breaking a type into two different types: a lightweight type with a Finalize method that doesn’t refer to any other objects, and a separate type without a Finalize method that does refer to other objects.
    • You have no control over when the Finalize method will execute. The object may hold on to resources until the next time the garbage collector runs.
    • When an application terminates, some objects are still reachable and will not have their Finalize method called. This can happen if background threads are using the objects or if objects are created during application shutdown or AppDomain unloading. In addition, by default, Finalize methods are not called for unreachable objects when an application exits so that the application may terminate quickly. Of course, all operating system resources will be reclaimed, but any objects in the managed heap are not able to clean up gracefully. You can change this default behavior by calling the System.GC type’s RequestFinalizeOnShutdown method. However, you should use this method with care since calling it means that your type is controlling a policy for the entire application.
    • The runtime doesn’t make any guarantees as to the order in which Finalize methods are called. For example, let’s say there is an object that contains a pointer to an inner object. The garbage collector has detected that both objects are garbage. Furthermore, say that the inner object’s Finalize method gets called first. Now, the outer object’s Finalize method is allowed to access the inner object and call methods on it, but the inner object has been finalized and the results may be unpredictable. For this reason, it is strongly recommended that Finalize methods not access any inner, member objects.

     

    If you determine that your type must implement a Finalize method, then make sure the code executes as quickly as possible. Avoid all actions that would block the Finalize method, including any thread synchronization operations. Also, if you let any exceptions escape the Finalize method, the system just assumes that the Finalize method returned and continues calling other objects’ Finalize methods.

    Finalization Internals

     
    When an application creates a new object, the new operator allocates the memory from the heap. If the object’s type contains a Finalize method, then a pointer to the object is placed on the finalization queue. The finalization queue is an internal data structure controlled by the garbage collector. Each entry in the queue points to an object that should have its Finalize method called before the object’s memory can be reclaimed.
    Figure 5 shows a heap containing several objects. Some of these objects are reachable from the application’s roots, and some are not. When objects C, E, F, I, and J were created, the system detected that these objects had Finalize methods and pointers to these objects were added to the finalization queue.

     

    Figure 5 A Heap with Many Objects

     

    When a GC occurs, objects B, E, G, H, I, and J are determined to be garbage. The garbage collector scans the finalization queue looking for pointers to these objects. When a pointer is found, the pointer is removed from the finalization queue and appended to the freachable queue (pronounced “F-reachable”). The freachable queue is another internal data structure controlled by the garbage collector. Each pointer in the freachable queue identifies an object that is ready to have its Finalize method called.
    After the collection, the managed heap looks like Figure 6. Here, you see that the memory occupied by objects B, G, and H has been reclaimed because these objects did not have a Finalize method that needed to be called. However, the memory occupied by objects E, I, and J could not be reclaimed because their Finalize method has not been called yet.

    Figure 6 Managed Heap after Garbage Collection

     

    There is a special runtime thread dedicated to calling Finalize methods. When the freachable queue is empty (which is usually the case), this thread sleeps. But when entries appear, this thread wakes, removes each entry from the queue, and calls each object’s Finalize method. Because of this, you should not execute any code in a Finalize method that makes any assumption about the thread that’s executing the code. For example, avoid accessing thread local storage in the Finalize method.
    The interaction of the finalization queue and the freachable queue is quite fascinating. First, let me tell you how the freachable queue got its name. The f is obvious and stands for finalization; every entry in the freachable queue should have its Finalize method called. The “reachable” part of the name means that the objects are reachable. To put it another way, the freachable queue is considered to be a root just like global and static variables are roots. Therefore, if an object is on the freachable queue, then the object is reachable and is not garbage.

    In short, when an object is not reachable, the garbage collector considers the object garbage. Then, when the garbage collector moves an object’s entry from the finalization queue to the freachable queue, the object is no longer considered garbage and its memory is not reclaimed. At this point, the garbage collector has finished identifying garbage. Some of the objects identified as garbage have been reclassified as not garbage. The garbage collector compacts the reclaimable memory and the special runtime thread empties the freachable queue, executing each object’s Finalize method.

     

    Figure 7 Managed Heap after Second Garbage Collection

    The next time the garbage collector is invoked, it sees that the finalized objects are truly garbage, since the application’s roots don’t point to it and the freachable queue no longer points to it. Now the memory for the object is simply reclaimed. The important thing to understand here is that two GCs are required to reclaim memory used by objects that require finalization. In reality, more than two collections may be necessary since the objects could get promoted to an older generation. Figure 7 shows what the managed heap looks like after the second GC.

    Resurrection

     
    The whole concept of finalization is fascinating. However, there is more to it than what I’ve described so far. You’ll notice in the previous section that when an application is no longer accessing a live object, the garbage collector considers the object to be dead. However, if the object requires finalization, the object is considered live again until it is actually finalized, and then it is permanently dead. In other words, an object requiring finalization dies, lives, and then dies again. This is a very interesting phenomenon called resurrection. Resurrection, as its name implies, allows an object to come back from the dead.

    I’ve already described a form of resurrection. When the garbage collector places a reference to the object on the freachable queue, the object is reachable from a root and has come back to life. Eventually, the object’s Finalize method is called, no roots point to the object, and the object is dead forever after. But what if an object’s Finalize method executed code that placed a pointer to the object in a global or static variable?
    public class BaseObj {
    protected override void Finalize() {
    Application.ObjHolder = this;
    }
    }

    class Application {
    static public Object ObjHolder;    // Defaults to null
    }
    In this case, when the object’s Finalize method executes, a pointer to the object is placed in a root and the object is reachable from the application’s code. This object is now resurrected and the garbage collector will not consider the object to be garbage. The application is free to use the object, but it is very important to note that the object has been finalized and that using the object may cause unpredictable results. Also note: if BaseObj contained members that pointed to other objects (either directly or indirectly), all objects would be resurrected, since they are all reachable from the application’s roots. However, be aware that some of these other objects may also have been finalized.

    In fact, when designing your own object types, objects of your type can get finalized and resurrected totally out of your control. Implement your code so that you handle this gracefully. For many types, this means keeping a Boolean flag indicating whether the object has been finalized or not. Then, if methods are called on your finalized object, you might consider throwing an exception. The exact technique to use depends on your type.

    Now, if some other piece of code sets Application.ObjHolder to null, the object is unreachable. Eventually the garbage collector will consider the object to be garbage and will reclaim the object’s storage. Note that the object’s Finalize method will not be called because no pointer to the object exists on the finalization queue.
    There are very few good uses of resurrection, and you really should avoid it if possible. However, when people do use resurrection, they usually want the object to clean itself up gracefully every time the object dies. To make this possible, the GC type offers a method called ReRegisterForFinalize, which takes a single parameter: the pointer to an object.
    public class BaseObj {
    protected override void Finalize() {
    Application.ObjHolder = this;
    GC.ReRegisterForFinalize(this);
    }
    }
    When this object’s Finalize method is called, it resurrects itself by making a root point to the object. The Finalize method then calls ReRegisterForFinalize, which appends the address of the specified object (this) to the end of the finalization queue. When the garbage collector detects that this object is unreachable again, it will queue the object’s pointer on the freachable queue and the Finalize method will get called again. This specific example shows how to create an object that constantly resurrects itself and never dies, which is usually not desirable. It is far more common to conditionally set a root to reference the object inside the Finalize method.

    Forcing an Object to Clean Up

     

    If you can, you should try to define objects that do not require any clean up. Unfortunately, for many objects, this is simply not possible. So for these objects, you must implement a Finalize method as part of the type’s definition. However, it is also recommended that you add an additional method to the type that allows a user of the type to explicitly clean up the object when they want. By convention, this method should be called Close or Dispose.
    In general, you use Close if the object can be reopened or reused after it has been closed. You also use Close if the object is generally considered to be closed, such as a file. On the other hand, you would use Dispose if the object should no longer be used at all after it has been disposed. For example, to delete a System.Drawing.Brush object, you call its Dispose method. Once disposed, the Brush object cannot be used, and calling methods to manipulate the object may cause exceptions to be thrown. If you need to work with another Brush, you must construct a new Brush object.

    Now, let’s look at what the Close/Dispose method is supposed to do. The System.IO.FileStream type allows the user to open a file for reading and writing. To improve performance, the type’s implementation makes use of a memory buffer. Only when the buffer fills does the type flush the contents of the buffer to the file. Let’s say that you create a new FileStream object and write just a few bytes of information to it. If these bytes don’t fill the buffer, then the buffer is not written to disk. The FileStream type does implement a Finalize method, and when the FileStream object is collected the Finalize method flushes any remaining data from memory to disk and then closes the file.

    But this approach may not be good enough for the user of the FileStream type. Let’s say that the first FileStream object has not been collected yet, but the application wants to create a new FileStream object using the same disk file. In this scenario, the second FileStream object will fail to open the file if the first FileStream object had the file open for exclusive access. The user of the FileStream object must have some way to force the final memory flush to disk and to close the file.

    If you examine the FileStream type’s documentation, you’ll see that it has a method called Close. When called, this method flushes the remaining data in memory to the disk and closes the file. Now the user of a FileStream object has control of the object’s behavior.

    But an interesting problem arises now: what should the FileStream’s Finalize method do when the FileStream object is collected? Obviously, the answer is nothing. In fact, there is no reason for the FileStream’s Finalize method to execute at all if the application has explicitly called the Close method. You know that Finalize methods are discouraged, and in this scenario you’re going to have the system call a Finalize method that should do nothing. It seems like there ought to be a way to suppress the system’s calling of the object’s Finalize method. Fortunately, there is. The System.GC type contains a static method, SuppressFinalize, that takes a single parameter, the address of an object.

    Figure 8 FileStream’s Type Implementation

    public class FileStream : Stream {

    public override void Close() {
    // Clean up this object: flush data and close file
    •••
    // There is no reason to Finalize this object now
    GC.SuppressFinalize(this);
    }

    protected override void Finalize() {
    Close();    // Clean up this object: flush data and close file
    }

    // Rest of FileStream methods go here
    •••
    }

    Figure 8 shows FileStream’s type implementation. When you call SuppressFinalize, it turns on a bit flag associated with the object. When this flag is on, the runtime knows not to move this object’s pointer to the freachable queue, preventing the object’s Finalize method from being called.
    Let’s examine another related issue. It is very common to use a StreamWriter object with a FileStream object.

    FileStream fs = new FileStream(“C:\SomeFile.txt”, FileMode.Open, FileAccess.Write, FileShare.Read);
    StreamWriter sw = new StreamWriter(fs);
    sw.Write (“Hi there”);

    // The call to Close below is what you should do
    sw.Close();
    // NOTE: StreamWriter.Close closes the FileStream. The FileStream
    //       should not be explicitly closed in this scenario
    Notice that the StreamWriter’s constructor takes a FileStream object as a parameter. Internally, the StreamWriter object saves the FileStream’s pointer. Both of these objects have internal data buffers that should be flushed to the file when you’re finished accessing the file. Calling the StreamWriter’s Close method writes the final data to the FileStream and internally calls the FileStream’s Close method, which writes the final data to the disk file and closes the file. Since StreamWriter’s Close method closes the FileStream object associated with it, you should not call fs.Close yourself.
    What do you think would happen if you removed the two calls to Close? Well, the garbage collector would correctly detect that the objects are garbage and the objects would get finalized. But, the garbage collector doesn’t guarantee the order in which the Finalize methods are called. So if the FileStream gets finalized first, it closes the file. Then when the StreamWriter gets finalized, it would attempt to write data to the closed file, raising an exception. Of course, if the StreamWriter got finalized first, then the data would be safely written to the file.

    How did Microsoft solve this problem? Making the garbage collector finalize objects in a specific order is impossible because objects could contain pointers to each other and there is no way for the garbage collector to correctly guess the order to finalize these objects. So, here is Microsoft’s solution: the StreamWriter type doesn’t implement a Finalize method at all. Of course, this means that forgetting to explicitly close the StreamWriter object guarantees data loss. Microsoft expects that developers will see this consistent loss of data and will fix the code by inserting an explicit call to Close.
    As stated earlier, the SuppressFinalize method simply sets a bit flag indicating that the object’s Finalize method should not be called. However, this flag is reset when the runtime determines that it’s time to call a Finalize method. This means that calls to ReRegisterForFinalize cannot be balanced by calls to SuppressFinalize. The code in Figure 9 demonstrates exactly what I mean.
    Figure 9 ReRegisterForFinalize and SuppressFinalize
    void method() {
    // The MyObj type has a Finalize method defined for it
    // Creating a MyObj places a reference to obj on the finalization table.
    MyObj obj = new MyObj();

    // Append another 2 references for obj onto the finalization table.
    GC.ReRegisterForFinalize(obj);
    GC.ReRegisterForFinalize(obj);

    // There are now 3 references to obj on the finalization table.

    // Have the system ignore the first call to this object’s Finalize
    // method.
    GC.SuppressFinalize(obj);

    // Have the system ignore the first call to this object’s Finalize
    // method.
    GC.SuppressFinalize(obj);   // In effect, this line does absolutely
    // nothing!

    obj = null;   // Remove the strong reference to the object.

    // Force the GC to collect the object.
    GC.Collect();

    // The first call to obj’s Finalize method will be discarded but
    // two calls to Finalize are still performed.
    }

    ReRegisterForFinalize and SuppressFinalize are implemented the way they are for performance reasons. As long as each call to SuppressFinalize has an intervening call to ReRegisterForFinalize, everything works. It is up to you to ensure that you do not call ReRegisterForFinalize or SuppressFinalize multiple times consecutively, or multiple calls to an object’s Finalize method can occur.

    Weak References

     

    When a root points to an object, the object cannot be collected because the application’s code can reach the object. When a root points to an object, it’s called a strong reference to the object. However, the garbage collector also supports weak references. Weak references allow the garbage collector to collect the object, but they also allow the application to access the object. How can this be? It all comes down to timing.

    If only weak references to an object exist and the garbage collector runs, the object is collected and when the application later attempts to access the object, the access will fail. On the other hand, to access a weakly referenced object, the application must obtain a strong reference to the object. If the application obtains this strong reference before the garbage collector collects the object, then the garbage collector can’t collect the object because a strong reference to the object exists. I know this all sounds somewhat confusing, so let’s clear it up by examining the code in Figure 1b.
    Figure 1b Strong and Weak References

    Void Method() {
    Object o = new Object();    // Creates a strong reference to the
    // object.

    // Create a strong reference to a short WeakReference object.
    // The WeakReference object tracks the Object.
    WeakReference wr = new WeakReference(o);

    o = null;    // Remove the strong reference to the object

    o = wr.Target;
    if (o == null) {
    // A GC occurred and Object was reclaimed.
    } else {
    // a GC did not occur and we can successfully access the Object
    // using o
    }
    }

    Why might you use weak references? Well, there are some data structures that are created easily, but require a lot of memory. For example, you might have an application that needs to know all the directories and files on the user’s hard drive. You can easily build a tree that reflects this information and as your application runs, you’ll refer to the tree in memory instead of actually accessing the user’s hard disk. This procedure greatly improves the performance of your application.
    The problem is that the tree could be extremely large, requiring quite a bit of memory. If the user starts accessing a different part of your application, the tree may no longer be necessary and is wasting valuable memory. You could delete the tree, but if the user switches back to the first part of your application, you’ll need to reconstruct the tree again. Weak references allow you to handle this scenario quite easily and efficiently.

    When the user switches away from the first part of the application, you can create a weak reference to the tree and destroy all strong references. If the memory load is low for the other part of the application, then the garbage collector will not reclaim the tree’s objects. When the user switches back to the first part of the application, the application attempts to obtain a strong reference for the tree. If successful, the application doesn’t have to traverse the user’s hard drive again.

    The WeakReference type offers two constructors:
    WeakReference(Object target);
    WeakReference(Object target, Boolean trackResurrection);
    The target parameter identifies the object that the WeakReference object should track. The trackResurrection parameter indicates whether the WeakReference object should track the object after it has had its Finalize method called. Usually, false is passed for the trackResurrection parameter and the first constructor creates a WeakReference that does not track resurrection.
    For convenience, a weak reference that does not track resurrection is called a short weak reference, while a weak reference that does track resurrection is called a long weak reference. If an object’s type doesn’t offer a Finalize method, then short and long weak references behave identically. It is strongly recommended that you avoid using long weak references. Long weak references allow you to resurrect an object after it has been finalized and the state of the object is unpredictable.

    Once you’ve created a weak reference to an object, you usually set the strong reference to the object to null. If any strong reference remains, the garbage collector will be unable to collect the object.

    To use the object again, you must turn the weak reference into a strong reference. You accomplish this simply by calling the WeakReference object’s Target property and assigning the result to one of your application’s roots. If the Target property returns null, then the object was collected. If the property does not return null, then the root is a strong reference to the object and the code may manipulate the object. As long as the strong reference exists, the object cannot be collected.

    Weak Reference Internals

     

    From the previous discussion, it should be obvious that WeakReference objects do not behave like other object types. Normally, if your application has a root that refers to an object and that object refers to another object, then both objects are reachable and the garbage collector cannot reclaim the memory in use by either object. However, if your application has a root that refers to a WeakReference object, then the object referred to by the WeakReference object is not considered reachable and may be collected.

    To fully understand how weak references work, let’s look inside the managed heap again. The managed heap contains two internal data structures whose sole purpose is to manage weak references: the short weak reference table and the long weak reference table. These two tables simply contain pointers to objects allocated within the managed heap.

    Initially, both tables are empty. When you create a WeakReference object, an object is not allocated from the managed heap. Instead, an empty slot in one of the weak reference tables is located; short weak references use the short weak reference table and long weak references use the long weak reference table.

    Once an empty slot is found, the value in the slot is set to the address of the object you wish to track the object’s pointer is passed to the WeakReference’s constructor. The value returned from the new operator is the address of the slot in the WeakReference table. Obviously, the two weak reference tables are not considered part of an application’s roots or the garbage collector would not be able to reclaim the objects pointed to by the tables.

    Now, here’s what happens when a garbage collection (GC) runs:

    • The garbage collector builds a graph of all the reachable objects.
    • The garbage collector scans the short weak reference table. If a pointer in the table refers to an object that is not part of the graph, then the pointer identifies an unreachable object and the slot in the short weak reference table is set to null.
    • The garbage collector scans the finalization queue. If a pointer in the queue refers to an object that is not part of the graph, then the pointer identifies an unreachable object and the pointer is moved from the finalization queue to the freachable queue. At this point, the object is added to the graph since the object is now considered reachable.
    • The garbage collector scans the long weak reference table. If a pointer in the table refers to an object that is not part of the graph (which now contains the objects pointed to by entries in the freachable queue), then the pointer identifies an unreachable object and the slot is set to null.
    • The garbage collector compacts the memory, squeezing out the holes left by the unreachable objects.
      Once you understand the logic of the garbage collection process, it’s easy to understand how weak references work. Accessing the WeakReference’s Target property causes the system to return the value in the appropriate weak reference table’s slot. If null is in the slot, the object was collected.

    A short weak reference doesn’t track resurrection. This means that the garbage collector sets the pointer to null in the short weak reference table as soon as it has determined that the object is unreachable. If the object has a Finalize method, the method has not been called yet so the object still exists. If the application accesses the WeakReference object’s Target property, then null will be returned even though the object actually still exists.

    A long weak reference tracks resurrection. This means that the garbage collector sets the pointer to null in the long weak reference table when the object’s storage is reclaimable. If the object has a Finalize method, the Finalize method has been called and the object was not resurrected.

    Generations

     
    The GC developers are tweaking the garbage collector to improve its performance. One feature of the garbage collector that exists purely to improve performance is called generations. A generational garbage collector (also known as an ephemeral garbage collector) makes the following assumptions:

    • The newer an object is, the shorter its lifetime will be.
    • The older an object is, the longer its lifetime will be.
    • Newer objects tend to have strong relationships to each other and are frequently accessed around the same time.
    • Compacting a portion of the heap is faster than compacting the whole heap.
    • When initialized, the managed heap contains no objects. Objects added to the heap are said to be in generation 0, as you can see in Figure 8. Stated simply, objects in generation 0 are young objects that have never been examined by the garbage collector.

     

     

    Figure 8 Generation 0

     

    Now, if more objects are added to the heap, the heap fills and a garbage collection must occur. When the garbage collector analyzes the heap, it builds the graph of garbage (shown here in purple) and non-garbage objects. Any objects that survive the collection are compacted into the left-most portion of the heap. These objects have survived a collection, are older, and are now considered to be in generation 1 (see Figure 9).

     

    Figure 9 Generations 0 and 1

    As even more objects are added to the heap, these new, young objects are placed in generation 0. If generation 0 fills again, a GC is performed. This time, all objects in generation 1 that survive are compacted and considered to be in generation 2 (see Figure 10). All survivors in generation 0 are now compacted and considered to be in generation 1. Generation 0 currently contains no objects, but all new objects will go into generation 0.


     

    Figure 10 Generations 0, 1, and 2

    Currently, generation 2 is the highest generation supported by the runtime’s garbage collector. When future collections occur, any surviving objects currently in generation 2 simply stay in generation 2.

    Generational GC Performance Optimizations

     
    As I stated earlier, generational garbage collecting improves performance. When the heap fills and a collection occurs, the garbage collector can choose to examine only the objects in generation 0 and ignore the objects in any greater generations. After all, the newer an object is, the shorter its lifetime is expected to be. So, collecting and compacting generation 0 objects is likely to reclaim a significant amount of space from the heap and be faster than if the collector had examined the objects in all generations.
    This is the simplest optimization that can be obtained from generational GC. A generational collector can offer more optimizations by not traversing every object in the managed heap. If a root or object refers to an object in an old generation, the garbage collector can ignore any of the older objects’ inner references, decreasing the time required to build the graph of reachable objects. Of course, it is possible that an old object refers to a new object. So that these objects are examined, the collector can take advantage of the system’s write-watch support (provided by the Win32® GetWriteWatch function in Kernel32.dll). This support lets the collector know which old objects (if any) have been written to since the last collection. These specific old objects can have their references checked to see if they refer to any new objects.

    If collecting generation 0 doesn’t provide the necessary amount of storage, then the collector can attempt to collect the objects from generations 1 and 0. If all else fails, then the collector can collect the objects from all generations 2, 1, and 0. The exact algorithm used by the collector to determine which generations to collect is one of those areas that Microsoft will be tweaking forever.

    Most heaps (like the C runtime heap) allocate objects wherever they find free space. Therefore, if I create several objects consecutively, it is quite possible that these objects will be separated by megabytes of address space. However, in the managed heap, allocating several objects consecutively ensures that the objects are contiguous in memory.

    One of the assumptions stated earlier was that newer objects tend to have strong relationships to each other and are frequently accessed around the same time. Since new objects are allocated contiguously in memory, you gain performance from locality of reference. More specifically, it is highly likely that all the objects can reside in the CPU’s cache. Your application will access these objects with phenomenal speed since the CPU will be able to perform most of its manipulations without having cache misses which forces RAM access.

    Microsoft’s performance tests show that managed heap allocations are faster than standard allocations performed by the Win32 HeapAlloc function. These tests also show that it takes less than 1 millisecond on a 200Mhz Pentium to perform a full GC of generation 0. It is Microsoft’s goal to make GCs take no more time than an ordinary page fault.

    Direct Control with System.GC

     

    The System.GC type allows your application some direct control over the garbage collector. For starters, you can query the maximum generation supported by the managed heap by reading the GC.MaxGeneration property. Currently, the GC.MaxGeneration property always returns 2.

    It is also possible to force the garbage collector to perform a collection by calling one of the two methods shown here:
    void GC.Collect(Int32 Generation)
    void GC.Collect()
    The first method allows you to specify which generation to collect. You may pass any integer from 0 to GC.MaxGeneration, inclusive. Passing 0 causes generation 0 to be collected; passing 1 causes generation 1 and 0 to be collected; and passing 2 causes generation 2, 1, and 0 to be collected. The version of the Collect method that takes no parameters forces a full collection of all generations and is equivalent to calling:
    GC.Collect(GC.MaxGeneration);
    Under most circumstances, you should avoid calling any of the Collect methods; it is best to just let the garbage collector run on its own accord. However, since your application knows more about its behaviour than the runtime does, you could help matters by explicitly forcing some collections. For example, it might make sense for your application to force a full collection of all generations after the user saves his data file. I imagine Internet browsers performing a full collection when pages are unloaded. You might also want to force a collection when your application is performing other lengthy operations; this hides the fact that the collection is taking processing time and prevents a collection from occurring when the user is interacting with your application.

    The GC type also offers a WaitForPendingFinalizers method. This method simply suspends the calling thread until the thread processing the freachable queue has emptied the queue, calling each object’s Finalize method. In most applications, it is unlikely that you will ever have to call this method.

    Lastly, the garbage collector offers two methods that allow you to determine which generation an object is currently in:
    Int32 GetGeneration(Object obj)
    Int32 GetGeneration(WeakReference wr)
    The first version of GetGeneration takes an object reference as a parameter, and the second version takes a WeakReference reference as a parameter. Of course, the value returned will be somewhere between 0 and GC.MaxGeneration, inclusive.

    The code in Figure 5a will help you understand how generations work. It also demonstrates the use of the garbage collection methods just discussed.
    Figure 5a GC Methods Demonstration

     

    private static void GenerationDemo() {
    // Let’s see how many generations the GCH supports (we know it’s 2)
    Display(“Maximum GC generations: ” + GC.MaxGeneration);

    // Create a new BaseObj in the heap
    GenObj obj = new GenObj(“Generation”);

    // Since this object is newly created, it should be in generation 0
    obj.DisplayGeneration();    // Displays 0

    // Performing a garbage collection promotes the object’s generation
    Collect();
    obj.DisplayGeneration();    // Displays 1

    Collect();
    obj.DisplayGeneration();    // Displays 2

    Collect();
    obj.DisplayGeneration();    // Displays 2   (max generation)

    obj = null;         // Destroy the strong reference to this object

    Collect(0);         // Collect objects in generation 0
    WaitForPendingFinalizers();    // We should see nothing

    Collect(1);         // Collect objects in generation 1
    WaitForPendingFinalizers();    // We should see nothing

    Collect(2);         // Same as Collect()
    WaitForPendingFinalizers();    // Now, we should see the Finalize
    // method run

    Display(-1, “Demo stop: Understanding Generations.”, 0);
    }

    Performance for Multithreaded Applications

    In the previous section, I explained the GC algorithm and optimizations. However, there was a big assumption made during that discussion: only one thread is running. In the real world, it is quite likely that multiple threads will be accessing the managed heap or at least manipulating objects allocated within the managed heap. When one thread sparks a collection, other threads must not access any objects (including object references on its own stack) since the collector is likely to move these objects, changing their memory locations.

    So, when the garbage collector wants to start a collection, all threads executing managed code must be suspended. The runtime has a few different mechanisms that it uses to safely suspend threads so that a collection may be done. The reason there are multiple mechanisms is to keep threads running as long as possible and to reduce overhead as much as possible. I don’t want to go into all the details here, but suffice it to say that Microsoft has done a lot of work to reduce the overhead involved with performing a collection. Microsoft will continue to modify these mechanisms over time to help ensure efficient garbage collections.

    The following paragraphs describe a few of the mechanisms that the garbage collector employs when applications have multiple threads:
    Fully Interruptible Code When a collection starts, the collector suspends all application threads. The collector then determines where a thread got suspended and using tables produced by the just-in-time (JIT) compiler, the collector can tell where in a method the thread stopped, what object references the code is currently accessing, and where those references are held (in a variable, CPU register, and so on).

    Hijacking The collector can modify a thread’s stack so that the return address points to a special function. When the currently executing method returns, this special function will execute, suspending the thread. Stealing the thread’s execution path this way is referred to as hijacking the thread. When the collection is complete, the thread will resume and return to the method that originally called it.
    Safe Points As the JIT compiler compiles a method, it can insert calls to a special function that checks if a GC is pending. If so, the thread is suspended, the GC runs to completion, and the thread is then resumed. The position where the compiler inserts these method calls is called a GC safe point.

    Note that thread hijacking allows threads that are executing unmanaged code to continue execution while a garbage collection is occurring. This is not a problem since unmanaged code is not accessing objects on the managed heap unless the objects are pinned and don’t contain object references. A pinned object is one that the garbage collector is not allowed to move in memory. If a thread that is currently executing unmanaged code returns to managed code, the thread is hijacked and is suspended until the GC completes.

    In addition to the mechanisms I just mentioned, the garbage collector offers some additional improvements that enhance the performance of object allocations and collections when applications have multiple threads.

    Synchronization-free Allocations On a multiprocessor system, generation 0 of the managed heap is split into multiple memory arenas using one arena per thread. This allows multiple threads to make allocations simultaneously so that exclusive access to the heap is not required.
    Scalable Collections On a multiprocessor system running the server version of the execution engine (MSCorSvr.dll), the managed heap is split into several sections, one per CPU. When a collection is initiated, the collector has one thread per CPU; all threads collect their own sections simultaneously. The workstation version of the execution engine (MSCorWks.dll) doesn’t support this feature.

    Garbage-collecting Large Objects

     
    There is one more performance improvement that you might want to be aware of. Large objects (those that are 20,000 bytes or larger) are allocated from a special large object heap. Objects in this heap are finalized and freed just like the small objects I’ve been talking about. However, large objects are never compacted because shifting 20,000-byte blocks of memory down in the heap would waste too much CPU time.

    Note that all of these mechanisms are transparent to your application code. To you, the developer, it looks like there is just one managed heap; these mechanisms exist simply to improve application performance.

    Monitoring Garbage Collections

     

    The runtime team at Microsoft has created a set of performance counters that provide a lot of real-time statistics about the runtime’s operations. You can view these statistics via the Windows 2000 System Monitor ActiveX ® control. The easiest way to access the System Monitor control is to run PerfMon.exe and select the + toolbar button, causing the Add Counters dialog box to appear (see Figure 11).


     

    Figure 11 Adding Performance Counters

     

    To monitor the runtime’s garbage collector, select the COM+ Memory Performance object. Then, you can select a specific application from the instance list box. Finally, select the set of counters that you’re interested in monitoring and press the Add button followed by the Close button. At this point, the System Monitor will graph the selected real-time statistics. Figure 12 describes the function of each counter.

    Figure 12 Counters to Monitor

     

    Counter Description
    # Bytes in all Heaps Total bytes in heaps for generations 0, 1, and 2 and from the large object heap. This indicates how much memory the garbage collector is using to store allocated objects.
    # GC Handles Total number of current GC handles.
    # Gen 0 Collections Number of collections of generation 0 (youngest) objects.
    # Gen 1 Collections Number of collections of generation 1 objects.
    # Gen 2 Collections Number of collections of generation 2 (oldest) objects.
    # Induced GC Total number of times the GC was run because of an explicit call (such as from the Classlibs) instead of during an allocation.
    # Pinned Objects Not yet implemented.
    # of Sink Blocks in use Synchronization primitives use sink blocks. Sink block data belongs to an object and is allocated on demand.
    # Total committed Bytes Total committed bytes from all heaps.
    % Time in GC Total time since the last sample spent performing garbage collection, divided by total time since the last sample.
    Allocated Bytes/sec Rate of bytes per second allocated by the garbage collector. This is only updated at a garbage collection, not at each allocation. Since it is a rate, time between GCs will be 0.
    Finalization Survivors Number of garbage-collected classes that survive because their finalizer creates a reference to them.
    Gen 0 heap size Size of generation 0 (youngest) heap in bytes.
    Gen 0 Promoted Bytes/Sec Bytes per second that are promoted from generation 0 (youngest) to generation 1. Memory is promoted when it survives a garbage collection.
    Gen 1 heap size Size of generation 1 heap in bytes.
    Gen 1 Promoted Bytes/Sec Bytes per second that are promoted from generation 1 to generation 2 (oldest). Memory is promoted when it survives a garbage collection. Nothing is promoted from generation 2, since it is the oldest.
    Gen 2 heap size Size of generation 2 (oldest) heap in bytes.
    Large Object Heap size Size of the Large Object heap in bytes.
    Promoted Memory from Gen 0 Bytes of memory that survive garbage collection and are promoted from generation 0 to generation 1.
    Promoted Memory from Gen 1 Bytes of memory that survive garbage collection and are promoted from generation 1 to generation 2.

     

    Garbage Collection v4.0

    The .NET garbage collector is one of the areas of the .NET Framework that is extremely important and probably one of the least understood. There are a lot of articles written about it and there have been very few changes since .NET 1.0 was first released. (There have been changes with almost each release, but they have been relatively minor.)
    With .NET 4.0, however, there are some fairly substantial changes to the GC that will have some interesting performance implications (in a good way).
    For a quick review, the GC in .NET is a generational garbage collector with 3 generations. Generation 0 and 1 collections are very fast since the segment (called the ephemeral segment) is small while Generation 2 collections can be relatively slow.
    The changes in the server GC will probably only affect a small number of applications. However, the changes to the workstation GC (which is the default mode) will affect almost all .NET applications. In CLR 4, you can now subscribe to an event to be notified before a Generation 2 or Large Object Heap collection.
    try
    {
    // Register for a set of notifications.
    // Parameters require tuning. First is
    // for Gen2, second, Large Object Heap
    GC.RegisterForFullGCNotification(10, 10);

    // Start a thread using WaitForFullGCProc
    Thread thWaitForFullGC = new Thread(new ThreadStart(WaitForFullGCProc));
    thWaitForFullGC.Start();
    In all .NET Framework versions from 3.5SP1 and earlier, workstation GC used a concurrent collection method. This means that the GC can do most, but not all, of a Generation 2 collection without pausing managed code. It can’t, however, do a Generation 0 and Generation 1 collection at the same time as a Generation 2 collection.
    CLR 4.0 changes that to support background collection, which can do a Generation 0 and Generation 1 collection at the same time as a Generation 2 collection. This means that now only unusual circumstances should lead to long latency times.
    Background GC is an evolution to concurrent GC. The significance of background GC is we can do ephemeral GCs while a background GC is in progress if needed. As with concurrent GC, background GC is also only applicable to full GCs and ephemeral GCs are always done as blocking GCs, and a background GC is also done on its dedicated GC thread. The ephemeral GCs done while a background GC is in progress are called foreground GCs.

    *The credit for above mentioned article goes to Jeffrey Richter for publishing the contents on msdn magazine and Scott Dorman.

  • .Net CTS (Common Type System) Overview

    In this article you will learn what is CTS, primitive types, value type , reference type, boxing, unboxing, blittable , non nlittable types and how it impact performance.

    In Microsoft’s .NET Framework, the Common Type System (CTS) is a standard that specifies how Type definitions and specific values of Types are represented in computer memory. It is intended to allow programs written in different programming languages to easily share information. The CTS specifies no particular syntax or keywords, but instead defines a common set of types that can be used with many different language syntaxes. 

    For example CTS defines System.Int32 – 4 byte integer
    C# defines int as an alias of System.Int32
    string -> System.String
    object -> System.Object
     

    The specification for the CTS is contained in Ecma standard 335, “Common Language Infrastructure (CLI).” The CLI and the CTS were created by Microsoft, and the Microsoft .NET framework is an implementation of the standard.
    Functions of CTS 

    • To establish a framework that helps enable cross-language integration, type safety, and high performance code execution. 
    • To provide an object-oriented model that supports the complete implementation of many programming languages. 
    • To define rules that languages must follow, which helps ensure that objects written in different languages can interact with each other. 
    • The CTS also defines the rules that ensures that the data types of objects written in various languages are able to interact with each other. 
    • Languages supported by .NET can implement all or some common data types.

    Primitive Types

     
    Certain data types are used so commonly that many compilers allow your code to manipulate them using simplified syntax. For example, you could allocate an integer using the following syntax in C#:
    int a = new int(5);
    But I’m sure you’ll agree that declaring and initializing an integer using this syntax is rather cumbersome. Fortunately, many compilers (including C#) allow you to use syntax similar to the following instead:

    int a = 5;
    This certainly makes the code more readable. And, of course, the intermediate language (IL) that is generated when using either syntax is identical. Any data types directly supported by the compiler are called primitive types. Primitive types map directly to types that exist in the base class library. For example, in C# an int maps directly to the System.Int32 type.

    C# Primitive Type  BCL Type  Description 
    sbyte  System.SByte  Signed 8-bit value 
    byte  System.Byte  Unsigned 8-bit value 
    short  System.Int16  Signed 16-bit value 
    ushort  System.UInt16  Unsigned 16-bit value 
    int  System.Int32  Signed 32-bit value 
    uint  System.UInt32  Unsigned 32-bit value 
    long  System.Int64  Signed 64-bit value 
    ulong  System.UInt64  Unsigned 64-bit value 
    char  System.Char  16-bit Unicode character 
    float  System.Single  IEEE 32-bit float 
    double  System.Double  IEEE 64-bit float 
    bool  System.Boolean  A True/False value 
    decimal  System.Decimal  96-bit signed integer times 100 through 1028 (common for financial calculations where rounding errors can’t be tolerated) 
    string  System.String  String type 
    object  System.Object  Base of all types 

    Reference and Value Types

    The common type system supports two general categories of types: Value Type (lightweight types) & Reference Type.
    Reference types  : When an object is allocated from the managed heap, the new operator returns the memory address of the object. You usually store this address in a variable. This is called a reference type variable because the variable does not actually contain the object’s bits; instead, the variable refers to the object’s bits.

    There are some performance issues to consider when working with reference types. First, the memory must be allocated from the managed heap, which could force a garbage collection to occur. Second, reference types are always accessed via their pointers. So every time your code references any member of an object on the heap, code must be generated and executed to dereference the pointer in order to perform the desired action. This adversely affects both size and speed. Reference types can be self-describing types, pointer types, or interface types. The type of a reference type can be determined from values of self-describing types. Self-describing types are further split into arrays and class types. The class types are user-defined classes, boxed value types, and delegates.
    Eg. 

     // Reference Type (because of ‘class’)
     class  RectRef { public int x, y, cx, cy; }
     

    Value types : Value type objects cannot be allocated on the garbage-collected heap, and the variable representing the object does not contain a pointer to an object; the variable contains the object itself. Since the variable contains the object, a pointer does not have to be dereferenced in order to manipulate the object. This, of course, improves performance.Value types are either allocated on the stack or allocated inline in a structure. Value types can be built-in (implemented by the runtime), user-defined, or enumerations.
    Eg.
     // Value type (because of ‘struct’)
     struct RectVal { public int x, y, cx, cy; }
     

    RectRef rr1 = new RectRef();  // Allocated in heap
    RectVal rv1;                  // Allocated on stack (new optional)
    rr1.x = 10;                   // Pointer dereference
    rv1.x = 10;                   // Changed on stack 

    RectRef rr2 = rr1;            // Copies pointer only
    RectVal rv2 = rv1;            // Allocate on stack & copies members
    rr1.x = 20;                   // Changes rr1 and rr2
    rv1.x = 20;                   // Changes rv1, not rv2
     

    The Rectangle type is declared using struct instead of the more common class. In C#, a type declared using struct is a value type, while types declared using class are reference types. 

    When possible, you should use value types instead of reference types because your application’s performance will be better. In particular, you should declare a type as a value type if all of the following are true: 

    • The type acts like a primitive type.
    • The type doesn’t need to inherit from any other type.
    • The type will not have any other types derived from it.
    • Objects of the type are not frequently passed as method arguments since this would cause frequent memory copy operations, hurting performance. The next section on boxing and unboxing will explain this in more detail.

    The main advantage of value types is that they are not allocated in the managed heap. Of course, value types have several limitations compared with reference types. Here are some of the ways in which value types and reference types differ.Value type objects have two representations: an unboxed form and a boxed form. Reference types are always in a boxed form. Value types are implicitly derived from System.ValueType. This type offers the same methods as defined by System.Object. However, System.ValueType overrides the Equals method so that it returns true if the values of the two objects’ instance fields match. In addition, System.ValueType overrides the GetHashCode method so that it produces a hash code value using an algorithm that takes into account the values in the objects’ instance fields. When defining your own value types, it is highly recommended that you override and provide explicit implementations for the Equals and GetHashCode methods.
    Since you cannot declare a new value type or a new reference type using a value type as a base class, value types should not have virtual functions, cannot be abstract, and are implicitly sealed (a sealed type cannot be used as the base of a new type).
    Reference type variables contain the memory address of objects in the heap. By default, when a reference type variable is created, it is initialized to null, indicating that the reference type variable doesn’t currently point to a valid object. Attempting to use a null reference type variable causes a NullReferenceException exception. By contrast, value type variables always contain a value of the underlying type. By default, all members of the value type are initialized to zero. It is not possible to generate a NullReferenceException exception when accessing a value type. 

    When you assign a value type variable to another value type variable, a copy of the value is made. When you assign a reference type variable to another reference type variable, only the memory address is copied. Because of the previous point, two or more reference type variables may refer to a single object in the heap. This allows operations on one variable to affect the object referenced by the other variable. On the other hand, value type variables each have their own copy of the object’s data, and it is not possible for operations on one value type variable to affect another.
     

    There are rare situations when the runtime must initialize a value type and is unable to call its default constructor. For example, this can happen when a thread local value type must be allocated and initialized when an unmanaged thread first executes managed code. In this situation, the runtime can’t call the type’s constructor but still ensures that all members are initialized to zero or null. For this reason, it is recommended that you don’t define a parameterless constructor on a value type. In fact, the C# compiler (and others) consider this an error and won’t compile the code. This problem is rare, and it never occurs on reference types. There are no restrictions on parameterized constructors for both value types and reference types.
     

    Since unboxed value types are not allocated on the heap, the storage allocated for them is freed as soon as the method that defines an instance of the type is no longer active. This also means that unboxed value type objects cannot receive a notification when their memory is reclaimed. However, a boxed value type will have its Finalize method called when it is garbage-collected. You are strongly discouraged from implementing a value type with a Finalize method. Like a parameterless constructor, C# considers this an error and will not compile the source code.
    Boxing and Unboxing

     
    There are many situations in which it is convenient to treat a value type as a reference type. Let’s say that you wanted to create an ArrayList object (a type defined in the System.Collections namespace) to hold a set of Points. The code might look like
    // Declare a value type
    struct Point {
       public int x, y;
    }
     

    ArrayList a = new ArrayList();
       for (int i = 0; i < 10; i++) {
          Point p;                // Allocate a Point (not in the heap)
          p.x = p.y = i;          // Initialize the members in the value type
          a.Add(p);               // Box the value type and add the
                                  // reference to the array
       }
     

    When the Add method is called, memory is allocated in the heap for a Point object. The members currently residing in the Point value type (p) are copied into the newly allocated Point object. The address of the Point object (a reference type) is returned and is then passed to the Add method. The Point object will remain in the heap until it is garbage-collected. The Point value type variable (p) can be reused or freed since the ArrayList never knows anything about it. Boxing enables a unified view of the type system, where a value of any type can ultimately be treated as an object.
     The opposite of boxing is, of course, unboxing. Unboxing retrieves a reference to the value type (data fields) contained within an object. Internally, the following is what happens when a reference type is unboxed: 

    • The common language runtime first ensures that the reference type variable is not null and that it refers to an object that is a boxed value of the desired value type. If either test fails, then an InvalidCastException exception is generated.
    • If the types do match, then a pointer to the value type contained inside the object is returned. The value type that this pointer refers to does not include the usual overhead associated with a true object: a pointer to a virtual method table and a sync block.

    Note that boxing always creates a new object and copies the unboxed value’s bits to the object. On the other hand, unboxing simply returns a pointer to the data within a boxed object: no memory copy occurs. However, it is commonly the case that your code will cause the data pointed to by the unboxed reference to be copied anyway.The following code demonstrates boxing and unboxing:

    public static void Main() {
       Int32 v = 5;    // Create an unboxed value type variable
       Object o = v;   // o refers to a boxed version of v
       v = 123;        // Changes the unboxed value to 123
     

       Console.WriteLine(v + “, ” + (Int32) o);    // Displays “123, 5”
    }
     

    From this code, can you guess how many boxing operations occur? You might be surprised to discover that the answer is three! Let’s analyze the code carefully to really understand what’s going on.
    First, an Int32 unboxed value type (v) is created and initialized to 5. Then an Object reference type (o) is created and it wants to point to v. But reference types must always point to objects in the heap, so C# generated the proper IL code to box v and stored the address of the boxed version of v in o. Now 123 is unboxed and the referenced data is copied into the unboxed value type v; this has no effect on the boxed version of v, so the boxed version keeps its value of 5. Note that this example shows how o is unboxed (which returns a pointer to the data in o), and then the data in o is memory copied to the unboxed value type v. 

    Now, you have the call to WriteLine. WriteLine wants a String object passed to it but you don’t have a String object. Instead, you have these three items: an Int32 unboxed value type (v), a string, and an Int32 reference (or boxed) type (o). These must somehow be combined to create a String. To accomplish this, the C# compiler generates code that calls the String object’s static Concat method. There are several overloaded versions of Concat. All of them perform identically; the difference is in the number of parameters. Since you want to format a string from three items, the compiler chooses the following version of the Concat method:
    public static String Concat(Object arg0, Object arg1, Object arg2);
     

    For the first parameter, arg0, v is passed. But v is an unboxed value parameter and arg0 is an Object, so v must be boxed and the address to the boxed v is passed for arg0. For the arg1 parameter, the address of the “, ” string is passed, identifying the address of a String object. Finally, for the arg2 parameter, o (a reference to an Object) was cast to an Int32. This creates a temporary Int32 value type that receives the unboxed version of the value currently referred to by o. This temporary Int32 value type must be boxed once again with the memory address being passed for Concat’s arg2 parameter.
     

    Once Concat is called, it calls each of the specified object’s ToString methods and concatenates each object’s string representation. The String object returned from Concat is then passed to WriteLine to show the final result.

    I should point out that the generated IL code would be more efficient if the call to WriteLine were written as follows:
    Console.WriteLine(v + “, ” + o);    // Displays “123, 5”
    This line is identical to the previous version except that I’ve removed the (Int32) cast that preceded the variable o. This code is more efficient because o is already a reference type to an Object and its address may simply be passed to the Concat method. So, removing the cast saved both an unbox and a box operation.
     Here is another example that demonstrates boxing and unboxing:


    public static void Main() {
       Int32 v = 5;           // Create an unboxed value type variable
       Object o = v;          // o refers to the boxed version of v 

       v = 123;               // Changes the unboxed value type to 123
       Console.WriteLine(v);  // Displays “123” 

       v = (Int32) o;         // Unboxes o into v
       Console.WriteLine(v);  // Displays “5”
    }  

    How many boxing operations do you count in this code? The answer is one. There is only one boxing operation because there is a WriteLine method that accepts an Int32 as a parameter:
    public static void WriteLine(Int32 value);

    *Note : Stack or Heap

    It’s more complicated than you might think. Even your claim that “value types are allocated on the stack” isn’t correct. For example:

    class Foo
    {
        int x;
    }
    

    int is a value type, but the value for x will always be on the heap because it will be stored with the rest of the data for the instance of Foo which is a class.

    Remember the rule, Reference types always goes to the Heap, whereas Value Types always go where they were declared. If a Value Type is declared outside of a method, but inside a Reference Type it will be placed within the Reference Type on the Heap.

    you may be interested in article about C# heap/stack memory , but you might also want to read Eric Lippert’s blog post on “The stack is an implementation detail”. and here is another simple but powerfull article on stack vs heap

    Blittable/Non Blittable types 

    Blittable types are defined as having an identical presentation in memory for managed and unmanaged (COM) environments, and can be directly shared. Understanding the difference between blittable and non-blittable types can aid in using COM Interop or P/Invoke, two techniques for interoperability in .NET applications.
    By pinning the data in memory, the garbage collector will be prevented from moving it , allowing it to be shared in-place with the unmanaged application.This means that both managed and unmanaged code will alter the memory locations of these types in a consistent manner, and much less effort is required by the marshaler to maintain data integrity. The following are some examples of blittable types available in the .NET framework:

    • System.Byte
    • System.SByte
    • System.Int16
    • System.UInt16
    • System.Int32
    • System.UInt32
    • System.Int64
    • System.IntPtr
    • System.UIntPtr

    Additionally, one-dimensional arrays of these types as well as complex types containing only fields of these types are blittable.
    If a type is not one of the blittable types, then it is classified as non-blittable. The reason a type is considered non-blittable is that for one representation in managed memory, it may have several potential representations in unmanaged memory or vice-versa. Alternatively, there may be exactly one representation for the type in both managed and unmanaged memory. It is also often the case that there simply is no representation on one side or the other. The following are some commonly-used non-blittable types in the .NET framework:

    • System.Boolean
    • System.Char
    • System.Object
    • System.String

    There are many more blittable and non-blittable types, and user-defined types may fit in either category depending on how they are defined

    Interoperability overview


    Interoperability can be bidirectional sharing of data and methods between unmanaged code and managed .NET code. .NET provides two ways of interoperating between the two: COM Interop and P/Invoke. Though the methodology is different, in both cases marshalling (conversion between representations of data, formats for calling functions and formats for returning values) must take place. COM Interop deals with this conversion between managed code and COM objects, whereas P/Invoke handles interactions between managed code and Win32 code. The concept of blittable and non-blittable data types applies to both — specifically to the problem of converting data between managed and unmanaged memory. This marshalling is performed by the interop marshaller, which is invoked automatically by the CLR when needed.

  • .Net CLR Internals

    The CLR is described as the “execution engine” of .NET. It provides the environment within which the programs run. It’s this CLR that manages the execution of programs and provides core services, such as code compilation, memory allocation, thread management, and garbage collection. Through the Common Type System (CTS), it enforces strict type safety, and it ensures that the code is executed in a safe environment by enforcing code access security. The software version of .NET is actually the CLR version.

    The European Computer Manufacturers Association (ECMA) standard has defines the Common Language Specification (CLS); this enforces that software development languages should be interoperable between them. The code written in a CLS should be compliant with the code written in another CLS-compliant language. Because the code supported by CLS-compliant language should be compiled into an intermediate language (IL) code. The CLR  engine executes the IL code. This ensures interoperability between CLS-compliant languages.

    The ECMA standard, Common Language Infrastructure (CLI), defines the specifications for the infrastructure that the IL code needs for execution.The CLR is Implementation of CLI. The CLI provides a common type system (CTS) and services such as type safety, managed code execution and side by side execution.

    In my previous article (.Net CLR Overview) we have seen how CLR is get loaded when user executes .net executable on windows (say) platform.

    There are many components in CLR which are used to do specific tasks or functions of CLR.

    The above diagram show the various components of .Net CLR , Each component is responsible for specific functionality mentioned below.

    • Class Loader : It is used to load all the classes (MSIL Code) at runtime into CLR. The class loader component of the CLR uses metadata to locate specific classes within assemblies, either locally or across networks.
    • MSIL to Native compiler : It is a JIT (Just In Time) compiler it will convert MSIL code to native code.
    • Code Manager : It manages the code during execution.
    • Garbage Collector : Memory allocation and Garbage collector, this performs automatic memory management.
    • Security engine : this enforces security restrictions as code level security folder level and machine level security using tools provided by Microsoft .NET and using .NET Framework setting under control panel.
    • Type Checker : It enforces strict type checking.
    • Thread Support : It provides multithreading support to .Net applications.
    • Exception Manager : It provides mechanisum to handle execptions at runtime.
    • Debug Engine : Allows developer to debug different types of applications.
    • Com Marshaler : Allows .NET applications to exchange data with COM applications.
    • Base Class library support : Which provides the classes (types) that the applications need at run time.

    How it works

    When the .NET program is compiled, the output of the compiler is not an executable file but a file that contains a special type of code called  the Microsoft Intermediate Language (MSIL), which is a low-level set of instructions understood by the common language run time. This MSIL defines a set of portable instructions that are independent of any specific CPU. It’s the job of the CLR to translate this Intermediate code into a executable code when the program is executed making the program to run in any environment for which the CLR is implemented. And that’s how the .NET Framework achieves Portability. This MSIL is turned into executable code using a JIT (Just In Time) complier. The process goes like this, when .NET programs are executed, the CLR activates the JIT complier. The JIT complier converts MSIL into native code on a demand basis as each part of the program is needed. Thus the program executes as a native code even though it is compiled into MSIL making the program to run as fast as it would if it is compiled to native code but achieves the portability benefits of MSIL.

    We will cover CLR core features like garbage collector, Thread support,Exception manager,Debug engine,Security engine in next articles.

  • .Net CLR Overview

    The Microsoft .NET Framework is a software framework that can be installed on computers running Microsoft Windows operating systems. It includes a large library of coded solutions to common programming problems and a virtual machine that manages the execution of programs written specifically for the framework. The .NET Framework is a Microsoft offering and is intended to be used by most new applications created for the Windows platform.

    The framework’s Base Class Library provides a large range of features including user interface, data access, database connectivity, cryptography, web application development, numeric algorithms, and network communications. The class library is used by programmers, who combine it with their own code to produce applications.

    Programs written for the .NET Framework execute in a software environment that manages the program’s runtime requirements. Also part of the .NET Framework, this runtime environment is known as the Common Language Runtime (CLR). The CLR provides the appearance of an application virtual machine so that programmers need not consider the capabilities of the specific CPU that will execute the program. The CLR also provides other important services such as security, memory management, and exception handling. The class library and the CLR together constitute the .NET Framework.

    The Common Language Runtime (CLR) is the foundation of the .NET Framework. CLR act as an agent that manages code at execution time, providing core services such as memory management, thread management, and remoting, while also enforcing strict type safety and facilitates with code accuracy that ensure security and robustness. The concept of code management is a fundamental principle of the CLR. Code that targets the CLR is known as managed code, while code that does not target the CLR is known as unmanaged code.

    Developers using the CLR write code in a language such as C# or VB.NET. At compile time, a .NET compiler converts such code into CIL code. At runtime, the CLR’s just-in-time compiler converts the CIL code into code native to the operating system. Alternatively, the CIL code can be compiled to native code in a separate step prior to runtime by using the Native Image Generator (NGEN). This speeds up all later runs of the software as the CIL-to-native compilation is no longer necessary.

    •  The .NET Framework provides a run-time environment called the common language runtime, which runs the code and provides services that make the development process easier.
    • The core runtime engine in the Microsoft .NET Framework for executing applications.
    • The common language runtime supplies managed code with services such as cross-language integration, code access security, object lifetime management, resouce management, type safety, pre-emptive threading, metadata services (type reflection), and debugging and profiling support.
    • The CLR is a multi-language execution environment. There are currently over 15 compilers being built by Microsoft and other companies that produce code that will execute in the CLR.
    • It is Microsoft’s implementation of the Common Language Infrastructure (CLI) standard, which defines an execution environment for program code.
    • In the CLR, code is expressed in a form of bytecode called the Common Intermediate Language (CIL, previously known as MSIL—Microsoft Intermediate Language).
    • You can create source code files using any programming language that supports the CLR. Then, you
      use the corresponding compiler to check syntax and analyze the source code. Regardless of which compiler you use, the
      result is a managed module. A managed module is a standard Windows portable executable (PE) file that requires the
      CLR to execute.

    A Managed Module is composed of the following parts:

    PE header : This is the standard Windows PE file header, which is similar to the Common Object File Format (COFF) header. The PE header indicates the type of file–GUI, CUI, or DLL—and also has a timestamp indicating when the file was built. For modules that contain only IL code (see below, Intermediate Language Code), the bulk of the information in the PE header is ignored. For modules that contain native CPU code, this header contains information about the native CPU code.

    CLR header : This header contains the information (interpreted by the CLR and utilities) that makes this a managed module. It includes the version of the CLR required, some flags, the MethodDef metadata token of the managed module’s entry point method (Main method), and the location/size of the module’s metadata, resources, strong name, some flags, and other less interesting stuff.

    MetaData : Every managed module contains metadata tables, of which there are 2 main types: those that describe the types and members defined in your source code, and those that describe the types and members referenced by your source code.

     Intermediate Language (IL) Code : This is the code that was produced by the compiler as it compiled the source code. IL is later compiled by the CLR into native CPU instructions.

    Most compilers of the past produced code targeted to a specific CPU architecture, such as x86, IA64, Alpha, or PowerPC. All CLR-compliant compilers produce intermediate language (IL) code instead. IL code is sometimes referred to as managed code, because its lifetime and execution are managed by the CLR.

    In brief, metadata is simply a set of data tables that describe what is defined in the module, such as types and
    their members.The metadata is always embedded in the same EXE/DLL as the code, making it impossible to separate the two. Since the metadata and code are produced by the compiler at the same time and are bound into the resulting managed module, the metadata and the IL code it describes are never out of sync with one another.
    Metadata has many uses. Here are some of them:

    • Metadata removes the need for header and library files when compiling, because all the information about the referenced types/members is contained in one file along with the IL that implements those type/members. Compilers can read metadata directly from managed modules.
    • Visual Studio uses metadata to help you write code. Its IntelliSense feature parses metadata to tell you what methods a type offers and what parameters that method expects.
    • The CLR code verification process uses metadata to ensure that your code performs only “safe” operations. Verification is discussed shortly.
    • Metadata allows an object’s fields to be serialized into a memory block, remoted to another machine, and then deserialized, recreating the object and its state on the remote machine.
    • Metadata allows the garbage collector to track the lifetime of objects. For any object, the garbage collector can determine the type of the object, and from the metadata it knows which fields within that object refer to other objects.

    The CLR doesn’t actually work with modules; it works with assemblies. An assembly is an abstract concept, which can be difficult to grasp at first. First, an assembly is a logical grouping of one or more managed modules or resource files. Second, an assembly is the smallest unit of reuse, security, and versioning. Depending on the choices you make with your compilers or tools, you can produce a single-file assembly or you can produce a multi-file assembly.

    Loading the Common Language Runtime

    When you build an EXE assembly, the compiler/linker emits some special information into the resulting assembly’s PE File header and the file’s .text section. When the EXE file is invoked, this special information causes the CLR to load and initialize. Then the CLR locates the entry point method for the application and lets the application start executing. 

    How a managed EXE loads and initializes the CLR.

    When the compiler/linker creates an executable assembly, the following 6-byte x86 stub function is emitted into the .text section of the PE file: JMP _CorExeMain The _CorExeMain function is imported from the Microsoft MSCorEE.dll dynamic-link library, and therefore MSCorEE.dll is referenced in the import (.idata) section of the assembly file. (MSCorEE.dll stands for Microsoft Component Object Runtime Execution Engine.) When the managed EXE file is invoked, Windows treats it just like any normal (unmanaged) EXE file: the Windows loader loads the file and examines the .idata section to see that MSCorEE.dll should be loaded into the process’s address space. Then, the loader obtains the address of the _CorExeMain function inside MSCorEE.dll and fixes up the stub function’s JMP instruction in the managed EXE file. The primary thread for the process begins executing this x86 stub function, which immediately jumps to _CorExeMain in MSCorEE.dll. _CorExeMain initializes the CLR and then looks at the CLR header for the executable assembly to determine what managed entry point method should execute. The IL code for the method is then compiled into native CPU instructions, after which the CLR jumps to the native code (using the process’s primary thread). At this point, the managed application code is running.

    The situation is similar for a managed DLL. When building a managed DLL, the compiler/linker emits a similar 6-byte x86 stub function for a DLL assembly in the .text section of the PE file: JMP _CorDllMain .  The _CorDllMain function is also imported from the MSCorEE.dll, causing the .idata section for the DLL to reference MSCorEE.dll. When Windows loads the DLL, it  automatically loads MSCorEE.dll (if it isn’t already loaded), obtains the address of the _CorDllMain function, and fixes up the 6 byte x86 JMP stub in the managed DLL. The thread that called LoadLibrary to load the managed DLL then jumps to the x86 stub in the managed DLL assembly, which immediately jumps to the _CorDllMain in MSCorEE.dll. _CorDllMain initializes the CLR (if it hasn’t already been initialized for the process) and then returns so that the application can continue executing as normal.

    We have shipped several versions of .Net framework: 1.0, 1.1, and 2.0 is on the horizon. All of them are side by side, meaning, someone may be using 1.0 CLR, at the same time, someone else is using 1.1 CLR. In the same process, there can be only one CLR. Once CLR is loaded in the process, it cannot be unloaded.

    Side by Side Execution 

    We have shipped several versions of .Net framework: 1.0, 1.1, 2.0,3.0,3.5 and 4.0 is on the horizon. All of them are side by side, meaning, someone may be using 2.0 CLR, at the same time, someone else is using 4.0 CLR. In the same process, there can be only one CLR (4.0 has new feature : In-process side by side (Inproc SxS) is the ability to run multiple versions of the CLR in a single process.). Once CLR is loaded in the process, it cannot be unloaded.

    So which CLR will my app use?

    It depends on which .Net framework has installed, and which framework your app is built with.

    The real component to determine which CLR to load is mscoree.dll, residing  in %windir%system32. When you install .Net framework, it will replace mscoree.dll if the existing one is older then the one it carries, and it will leave it alone if the existing one is newer. So we always have the latest mscoree.dll in %windir%system32, even the corresponding .Net framework has been uninstalled. For this reason, mscoree.dll has to maintain very strict compatibility.

     Because we always have the latest mscoree.dll, the following discussion is based on what newest .Net framework you have ever installed.

     If only 1.0 is installed, then 1.0 CLR will always be used. 1.0 mscoree.dll is not side by side aware.

     If 1.1 is installed, then the CLR you built with will be loaded. If you built your app with 1.0, then 1.0 CLR will be loaded. If you built your app with 1.1, then 1.1 CLR will be loaded. If the required CLR is not available in your machine, mscoree.dll will bring up a dialog and quit. This is so that your app won’t run under a different CLR that you did not test.

     The thinking shifts in 2.0. In 2.0, mscoree.dll will try to use the CLR you built with first. If that CLR cannot be found, mscoree.dll will load 2.0 CLR to run your app. But if the CLR you built with is newer than (the currently installed) 2.0, mscoree.dll will bring up the same dialog and quit. The latter behavior is frequently seen in internal testing.

     For apps built with interim release, mscoree.dll maps it to the closest officially released CLR. So 1.0 beta2+ will use 1.0 CLR. 1.1 beta will use 1.1 CLR.

     Of course, you can use a config file to overwrite the default behavior.

    Microsoft has released CLR (2.0) source code Implementation of CLI (Common Language Infrastructure) – ECMA standard that describes the core of the .NET Framework world.The Shared Source CLI goes beyond the printed specification of the ECMA standards, providing a working implementation for CLI developers to explore and understand.

    Developers interested in the internal workings of the .NET Framework can explore this implementation of the CLI to see how garbage collection works, JIT compilation and verification is handled, security protocols implemented, and the organization of frameworks and virtual object systems.

    Jump to Next Part : .Net CLR Internals (CLR modules in detail..) 

  • Dependency Properties

    WPF introduces a new type of property called a dependency property, used throughout the platform to enable styling, automatic data binding, animation, and more. Definition of Dependency Properties on MSDN

    A dependency property depends on multiple providers for determining its value at any point in time. These providers could be an animation continuously changing its value, a parent element whose property value trickles down to its children, and so on. Arguably the biggest feature of a dependency property is its built-in ability to provide change notification. The motivation for adding such intelligence to properties is to enable rich functionality directly from declarative markup.

    Below is the demonstration of how Button effectively implements one of its dependency properties which is called IsDefault.

    public class Button : ButtonBase
    {
    // The dependency property
    public static readonly DependencyProperty IsDefaultProperty;
    static Button()
    {
    // Register the property
    Button.IsDefaultProperty = DependencyProperty.Register(“IsDefault”,
    typeof(bool), typeof(Button),
    new FrameworkPropertyMetadata(false,
    new PropertyChangedCallback(OnIsDefaultChanged)));
    …
    }
    // A .NET property wrapper (optional)
    public bool IsDefault
    {
    get { return (bool)GetValue(Button.IsDefaultProperty); }
    set { SetValue(Button.IsDefaultProperty, value); }
    }
    // A property changed callback (optional)
    private static void OnIsDefaultChanged(
    DependencyObject o, DependencyPropertyChangedEventArgs e) { … }
    …
    }

    The static IsDefaultProperty field is the actual dependency property, represented by the System.Windows.DependencyProperty class. By convention all DependencyProperty fields are public, static, and have a Property suffix.

    So one of the first things I thought was weird about the definition of a dependency property is that it is a static. This property needs to store info relevant to a particular instance of a class, how is it going to do that if it is static?

    As you read more about them, you will realized that a dependency property definition was exactly that – a definition. You are essentially saying that class A will have a property B – and it makes sense that that definition would be static. The actual storage of a value for a dependency property is deep inside the WPF property system – you never have to worry about it.

    Dependency properties are usually created by calling the static DependencyProperty.Register method, which requires a name (IsDefault), a property type (bool), and the type of the class claiming to own the property

    (Button). Optionally (via different overloads of Register), you can pass metadata that customizes how the property is treated by WPF, as well as callbacks for handling property value changes, coercing values, and validating values. Button calls an overload of Register in its static constructor to give the dependency property a default value of false and to attach a delegate for change notifications.

    Finally, the traditional .NET property called IsDefault implements its accessors by calling GetValue and SetValue methods inherited from System.Windows.DependencyObject, a low-level base class from which all classes with dependency properties must derive. GetValue returns the last value passed to SetValue or, if SetValue has never been called, the default value registered with the property.

    So at first glance, all the properties on the new WPF controls seem to be regular old properties. But don’t be fooled – this is often just a simple wrapper around a dependency property.

    The IsDefault .NET property (sometimes called a property wrapper) is not strictly necessary; consumers of Button could always directly call the GetValue/SetValue methods because they are exposed publicly. But the .NET property makes programmatic reading and writing of the property much more natural for consumers, and it enables the property to be set via XAML.

    GetValue and SetValue internally use an efficient sparse storage system and because IsDefaultProperty is a static field (rather than an instance field), the dependency property implementation saves per-instance memory compared to a typical .NET property. If all the properties on WPF controls were wrappers around instance fields (as most .NET properties are), they would consume a significant amount of memory because of all the local data attached to each instance. The benefits of the dependency property implementation extend to more than just

    memory usage, however. It centralizes and standardizes a fair amount of code that property implementers would have to write to check thread access, prompt the containing element to be re-rendered, and so on.

    Change Notification

    Whenever the value of a dependency property changes, WPF can automatically trigger a number of actions depending on the property’s metadata. These actions can be re-rendering the appropriate elements, updating the current layout, refreshing data bindings,and much more. One of the most interesting features enabled by this built-in change notification is property triggers, which enable you to perform your own custom actions when a property value changes without writing any procedural code.

    For example, imagine that you want the text in each Button to turn blue when the mouse pointer hovers over it. Without property triggers,you can attach two event handlers to each Button, one for its MouseEnter event and one

    for its MouseLeave event:

    <Button MouseEnter=”Button_MouseEnter” MouseLeave=”Button_MouseLeave”
    MinWidth=”75” Margin=”10”>Help</Button>
    <Button MouseEnter=”Button_MouseEnter” MouseLeave=”Button_MouseLeave”
    MinWidth=”75” Margin=”10”>OK</Button>

    These two handlers could be implemented in a C# code-behind file as follows:

    // Change the foreground to blue when the mouse enters the button
    void Button_MouseEnter(object sender, MouseEventArgs e)
    {
    Button b = sender as Button;
    if (b != null) b.Foreground = Brushes.Blue;
    }
    // Restore the foreground to black when the mouse exits the button
    void Button_MouseLeave(object sender, MouseEventArgs e)
    {
    Button b = sender as Button;
    if (b != null) b.Foreground = Brushes.Black;
    }

    With a property trigger, however, you can accomplish this same behavior purely in XAML. The following concise Trigger object is (just about) all you need:

    <Trigger Property=”IsMouseOver” Value=”True”>
    <Setter Property=”Foreground” Value=”Blue”/>
    </Trigger>

    This trigger can act upon Button’s IsMouseOver property, which becomes true at the same time the MouseEnter event is raised and false at the same time the MouseLeave event is raised. Note that you don’t have to worry about reverting Foreground to black when IsMouseOver changes to false. This is automatically done by WPF! You could apply the preceding Trigger to a Button by wrapping it in a few intermediate XML elements as follows:

    <Button MinWidth=”75” Margin=”10”>
    <Button.Style>
    <Style TargetType=”{x:Type Button}”>
    <Style.Triggers>
    <Trigger Property=”IsMouseOver” Value=”True”>
    <Setter Property=”Foreground” Value=”Blue”/>
    </Trigger>
    </Style.Triggers>
    </Style>
    </Button.Style>
    OK
    </Button>
    Three type of triggers are available in WPF

    Property Triggers : As mentioned above

    A data trigger is a form of property trigger that works for all .NET properties (not just dependency properties)

    An event trigger enables you to declaratively specify actions to take when a routed event. Event triggers always involve working with animations or sounds

    Property Value Inheritance

    The term property value inheritance or property inheritance doesn’t refer to traditional object oriented class based inheritance, but rather the flowing of property values down the element tree.

    Example :

    <Window xmlns=”http://schemas.microsoft.com/winfx/2006/xaml/presentation”
    
    Title=”Property Inheritance sample” SizeToContent=”WidthAndHeight”
    
    FontSize=30FontStyle=Italic”
    
    Background=”OrangeRed”>
    
    <StackPanel>
    
    <Label FontWeight=”Bold” FontSize=”20” Foreground=”White”>
    
    WPF Property Inheritance
    
    </Label>
    
    <Label>Rajneesh</Label>
    
    <Label>Tech</Label>
    
    <ListBox>
    
    <ListBoxItem>.Net</ListBoxItem>
    
    <ListBoxItem>C#</ListBoxItem>
    
    </ListBox>
    
    <StackPanel Orientation=”Horizontal” HorizontalAlignment=”Center”>
    
    <Button MinWidth=”75” Margin=”10”>Cancel</Button>
    
    <Button MinWidth=”75” Margin=”10”>OK</Button>
    
    </StackPanel>
    
    <StatusBar>You have successfully created property inheritance</StatusBar>
    
    </StackPanel>
    
    </Window>
    

    Note : Window automatically resizes to fit all the content thanks to its slick SizeToContent setting!

    In above example we are explicitly setting window FontSize and FontStyle dependency properties.

    For the most part, these two settings flow all the way down the tree and are inherited by children. This affects even the Buttons and ListBoxItems, which are three levels down the logical tree. The first Label’s FontSize does not change because it is explicitly marked with a FontSize of 20, overriding the inherited value of 30.

    Note : Internally, dependency properties can opt in to inheritance by passing FrameworkPropertyMetadataOptions. Inherits to DependencyProperty.Register

    Support for Multiple Providers

    WPF contains many powerful mechanisms that independently attempt to set the value of dependency properties.

    Attached Properties

    An attached property is a special form of dependency property that can effectively be attached to arbitrary objects.

    Imagine that rather than setting FontSize and FontStyle for the entire Window (in above example), you would rather set them on the inner StackPanel so they are inherited only by the two Buttons. But StackPanel doesn’t have any font-related properties of its own! Instead, you must use the FontSize and FontStyle attached properties that happen to be defined on a class called TextElement.

    <StackPanel TextElement.FontSize=”30” TextElement.FontStyle=”Italic”
    Orientation=”Horizontal” HorizontalAlignment=”Center”>
    <Button MinWidth=”75” Margin=”10”>Cancel</Button>
    <Button MinWidth=”75” Margin=”10”>OK</Button>
    </StackPanel>

    Just like previous technologies such as Windows Forms, many classes in WPF define a Tag property (of type System.Object) intended for storing arbitrary custom data with each instance. But attached properties are a more powerful and flexible mechanism for attaching custom data to any object deriving from DependencyObject. It’s often overlooked that attached properties enable you to effectively add custom data to instances of sealed classes.

    *Beginners : I would like to recommended WPF fundamental tutorials by Christian Moser at http://www.wpftutorial.net