Custom Search

Friday, September 19, 2008

.Net Framwork 3.5 Garbage Collection

Garbage Collection .NET Framework 3.5 [C#]

Source: MSDN

We should be aware of some critical terms & tweaks by which, we can tune the application memory management using GC, before we dive deep to Garbage

A. GC.Collect()
B. GC.WaitForPendingFinalizers()
C. GC.KeepAlive()
D. SupPresssFinalize()
E. Finalize()
F. Dispose()
G. Weak References
I. Latency Modes
J. Optimization for share web hosting



A. GC.Collect()

Use this method to try to reclaim all memory that is inaccessible.
All objects, regardless of how long they have been in memory, are considered for collection; however, objects that are referenced in managed code are not collected. Use this method to force the system to try to reclaim the maximum amount of available memory.


B. GC.WaitForPendingFinalizers()

When the garbage collector finds objects that can be reclaimed, it checks each object to determine the object's finalization requirements. If an object implements a finalizer and has not disabled finalization by calling SuppressFinalize, the object is placed in a list of objects that are marked as ready for finalization. The garbage collector calls the Finalize methods for the objects in this list and removes the entries from the list. This method blocks until all finalizers have run to completion.
The thread on which finalizers are run is unspecified, so there is no guarantee that this method will terminate. However, this thread can be interrupted by another thread while the WaitForPendingFinalizers method is in progress. For example, you can start another thread that waits for a period of time and then interrupts this thread if this thread is still suspended.

C. GC.KeepAlive()


The purpose of the KeepAlive method is to ensure the existence of a reference to an object that is at risk of being prematurely reclaimed by the garbage collector. A common scenario where this might happen is when there are no references to the object in managed code or data, but the object is still in use in unmanaged code such as Win32 APIs, unmanaged DLLs, or methods using COM.
This method references the obj parameter, making that object ineligible for garbage collection from the start of the routine to the point, in execution order, where this method is called. Code this method at the end, not the beginning, of the range of instructions where obj must be available.
The KeepAlive method performs no operation and produces no side effects other than extending the lifetime of the object passed in as a parameter.

For Example:

using System; using System.Threading; using System.Runtime.InteropServices;  
// A simple class that exposes two static Win32 functions. 
// One is a delegate type and the other is an enumerated type. 
public class MyWin32  {     
// Declare the SetConsoleCtrlHandler function      
// as external and receiving a delegate.        
[DllImport("Kernel32")]      
public static extern Boolean SetConsoleCtrlHandler(HandlerRoutine Handler, Boolean Add);      
// A delegate type to be used as the handler routine      
// for SetConsoleCtrlHandler.     
public delegate Boolean HandlerRoutine(CtrlTypes CtrlType);      
// An enumerated type for the control messages      
// sent to the handler routine.     
public enum CtrlTypes      {         
CTRL_C_EVENT = 0,         
CTRL_BREAK_EVENT,         
CTRL_CLOSE_EVENT,            
CTRL_LOGOFF_EVENT = 5,         
CTRL_SHUTDOWN_EVENT     
} 
}  

public class MyApp  
{     
// A private static handler function in the MyApp class.     
static Boolean Handler(MyWin32.CtrlTypes CtrlType)    
{         
String message = "This message should never be seen!";         
 // A switch to handle the event type.         
switch(CtrlType)         
{            
 case MyWin32.CtrlTypes.CTRL_C_EVENT:                 
message = "A CTRL_C_EVENT was raised by the user.";                 
break;             
case MyWin32.CtrlTypes.CTRL_BREAK_EVENT:                 
message = "A CTRL_BREAK_EVENT was raised by the user.";                 
break;            
case MyWin32.CtrlTypes.CTRL_CLOSE_EVENT:                    
message = "A CTRL_CLOSE_EVENT was raised by the user.";                 
break;             
case MyWin32.CtrlTypes.CTRL_LOGOFF_EVENT:                 
message = "A CTRL_LOGOFF_EVENT was raised by the user.";                 
break;             
case MyWin32.CtrlTypes.CTRL_SHUTDOWN_EVENT:                 
message = "A CTRL_SHUTDOWN_EVENT was raised by the user.";                 
break;         
}          
// Use interop to display a message for the type of event.         
Console.WriteLine(message);          
return true;     
}      

public static void Main()     
{                   
// Use interop to set a console control handler.         
MyWin32.HandlerRoutine hr = new MyWin32.HandlerRoutine(Handler);         
MyWin32.SetConsoleCtrlHandler(hr, true);          
// Give the user some time to raise a few events.         
Console.WriteLine("Waiting 30 seconds for console ctrl events...");          
// The object hr is not referred to again.         
// The garbage collector can detect that the object has no         
// more managed references and might clean it up here while         
// the unmanaged SetConsoleCtrlHandler method is still using it.                        
// Force a garbage collection to demonstrate how the hr         
// object will be handled.         
GC.Collect();         
GC.WaitForPendingFinalizers();         
GC.Collect();                 
Thread.Sleep(30000);          
// Display a message to the console when the unmanaged method         
// has finished its work.        
Console.WriteLine("Finished!");          
// Call GC.KeepAlive(hr) at this point to maintain a reference to hr.          
// This will prevent the garbage collector from collecting the          
// object during the execution of the SetConsoleCtrlHandler method.         
GC.KeepAlive(hr);            
Console.Read();     
} 
} 

D. SuppressFinalize
    Requests that the system not call the finalizer for the specified object. 
This method sets a bit in the object header, which the system checks when calling finalizers. The obj parameter is required to be the caller of this method.
Objects that implement the IDisposable interface can call this method from the IDisposable..::.Dispose method to prevent the garbage collector from calling Object..::.Finalize on an
object that does not require it.
For Example:
using System;
using System.ComponentModel;
// The following example demonstrates how to use the  
// GC.SuppressFinalize method in a resource class to prevent 
// the clean-up code for the object from being called twice.  
public class DisposeExample 
{     
// A class that implements IDisposable.     
// By implementing IDisposable, you are announcing that      
// instances of this type allocate scarce resources.     
public class MyResource: IDisposable     
{         
// Pointer to an external unmanaged resource.         
private IntPtr handle;         
// Other managed resource this class uses.         
private Component component = new Component();         
// Track whether Dispose has been called.         
private bool disposed = false;          
// The class constructor.         
public MyResource(IntPtr handle)         
{             
this.handle = handle;         
}          
// Implement IDisposable.         
// Do not make this method virtual.         
// A derived class should not be able to override this method.         
public void Dispose()         
{             
Dispose(true);             
// This object will be cleaned up by the Dispose method.             
// Therefore, you should call GC.SupressFinalize to             
// take this object off the finalization queue              
// and prevent finalization code for this object             
// from executing a second time.             
GC.SuppressFinalize(this);         
}          

// Dispose(bool disposing) executes in two distinct scenarios.         
// If disposing equals true, the method has been called directly         
// or indirectly by a user's code. Managed and unmanaged resources         
// can be disposed.         
// If disposing equals false, the method has been called by the          
// runtime from inside the finalizer and you should not reference          
// other objects. Only unmanaged resources can be disposed.         
private void Dispose(bool disposing)         
{             
// Check to see if Dispose has already been called.             
if(!this.disposed)             
{                 
// If disposing equals true, dispose all managed                  
// and unmanaged resources.                 
if(disposing)                 
{                     
// Dispose managed resources.                    
component.Dispose();                 
}                           
// Call the appropriate methods to clean up                  
// unmanaged resources here.                 
// If disposing is false,                  
// only the following code is executed.                 
CloseHandle(handle);                 
handle = IntPtr.Zero;                         
}             
disposed = true;                  
}          
// Use interop to call the method necessary           
// to clean up the unmanaged resource.         
[System.Runtime.InteropServices.DllImport("Kernel32")]         
private extern static Boolean CloseHandle(IntPtr handle);          
// Use C# destructor syntax for finalization code.         
// This destructor will run only if the Dispose method          
// does not get called.         
// It gives your base class the opportunity to finalize.         
// Do not provide destructors in types derived from this class.         
~MyResource()              
 {             
// Do not re-create Dispose clean-up code here.             
// Calling Dispose(false) is optimal in terms of             
// readability and maintainability.             
Dispose(false);         
}     
}      

public static void Main()     
{         
// Insert code here to create         
// and use a MyResource object.     
} 
} 

E. Finalize
Allows an Object to attempt to free resources and perform other cleanup operations before the Object is reclaimed by garbage collection.
Finalize is protected and, therefore, is accessible only through this class or a derived class.
This method is automatically called after an object becomes inaccessible, unless the object has been exempted from finalization by a call to SuppressFinalize. During shutdown of an application domain, Finalize is automatically called on objects that are not exempt from finalization, even those that are still accessible. Finalize is automatically called only once on a given instance, unless the object is re-registered using a mechanism such as ReRegisterForFinalize and GC.SuppressFinalize has not been subsequently called.
Every implementation of Finalize in a derived type must call its base type's implementation of Finalize. This is the only case in which application code is allowed to call Finalize.
Finalize operations have the following limitations:
    • The exact time when the finalizer executes during garbage collection is undefined.
    • Resources are not guaranteed to be released at any specific time, unless calling a Close
    • method or a Dispose method.
    • The finalizers of two objects are not guaranteed to run in any specific order, even if one
    • object refers to the other. That is, if Object A has a reference to Object B and both have
    • finalizers, Object B might have already finalized when the finalizer of Object A starts.
    • The thread on which the finalizer is run is unspecified.
The Finalize method might not run to completion or might not run at all in the following exceptional circumstances:
    • Another finalizer blocks indefinitely (goes into an infinite loop, tries to obtain a lock it can
    • never obtain and so on). Because the runtime attempts to run finalizers to completion,
    • other finalizers might not be called if a finalizer blocks indefinitely.
    • The process terminates without giving the runtime a chance to clean up. In this case,
    • the runtime's first notification of process termination is a DLL_PROCESS_DETACH notification.
The runtime continues to Finalize objects during shutdown only while the number of finalizable objects continues to decrease.
If Finalize or an override of Finalize throws an exception, and the runtime is not hosted by an application that overrides the default policy, the runtime terminates the process and no active try-finally blocks or finalizers are executed. This behavior ensures process integrity if the finalizer cannot free or destroy resources.
Notes to Implementers:
Object..::.Finalize does nothing by default. It must be overridden by a derived class only if necessary, because reclamation during garbage collection tends to take much longer if a Finalize operation must be run.
If an Object holds references to any resources, Finalize must be overridden by a derived class in order to free these resources before the Object is discarded during garbage collection.
A type must implement Finalize when it uses unmanaged resources such as file handles or database connections that must be released when the managed object that uses them is reclaimed. See the IDisposable interface for a complementary and more controllable means of disposing resources.
Finalize can take any action, including resurrecting an object (that is, making the object accessible again) after it has been cleaned up during garbage collection. However, the object can only be resurrected once; Finalize cannot be called on resurrected objects during garbage collection.
c#
Destructors are the C# mechanism for performing cleanup operations. Destructors provide appropriate safeguards, such as automatically calling the base type's destructor. In C# code, Object..::.Finalize cannot be called or overridden.
F. Dispose
The pattern for disposing an object, referred to as a dispose pattern, imposes order on the
lifetime of an object. A type's Dispose method should release all the resources that
it owns. It should also release all resources owned by its base types by calling its parent type's
Dispose method. The parent type's Dispose method should release all resources that it
owns and in turn call its parent type's Dispose method, propagating this pattern through the hierarchy
of base types. To help ensure that resources are always cleaned up appropriately,
a Dispose method should be callable multiple times without throwing an exception.
There is no performance benefit in implementing the Dispose method on types that use
only managed resources (such as arrays) because they are automatically reclaimed by the
garbage collector. Use the Dispose method primarily on managed objects that use native resources
and on COM objects that are exposed to the .NET Framework. Managed objects that
use native resources (such as the FileStream class) implement the IDisposable interface.
A Dispose method should call the SuppressFinalize method for the object it is disposing. If
the object is currently on the finalization queue, SuppressFinalize prevents its Finalize
method from being called. Remember that executing a Finalize method is costly to performance. If
your Dispose method has already done the work to clean up the object, then it is not
necessary for the garbage collector to call the object's Finalize method.
For Example:
using System; 
using System.IO;  
class Program 
{      
static void Main()     
{         
try         
{             
// Initialize a Stream resource to pass              
// to the DisposableResource class.             
Console.Write("Enter filename and its path: ");             
string fileSpec = Console.ReadLine();             
FileStream fs = File.OpenRead(fileSpec);             
DisposableResource TestObj = new DisposableResource(fs);              
// Use the resource.             
TestObj.DoSomethingWithResource();              
// Dispose the resource.             
TestObj.Dispose();          
}         
catch (FileNotFoundException e)         
{             
Console.WriteLine(e.Message);         
}    
 }
 }   
// This class shows how to use a disposable resource. 
// The resource is first initialized and passed to 
// the constructor, but it could also be 
// initialized in the constructor. 
// The lifetime of the resource does not  
// exceed the lifetime of this instance. 
// This type does not need a finalizer because it does not 
// directly create a native resource like a file handle 
// or memory in the unmanaged heap.  

public class DisposableResource : IDisposable 
{      
private Stream _resource;       
private bool _disposed;      
// The stream passed to the constructor      
// must be readable and not null.     
public DisposableResource(Stream stream)     
{         
if (stream == null)             
throw new ArgumentNullException("Stream in null.");         
if (!stream.CanRead)             
throw new ArgumentException("Stream must be readable.");          
_resource = stream;          
_disposed = false;    
 }      
// Demonstrates using the resource.      
// It must not be already disposed.    
public void DoSomethingWithResource() 
{         
if (_disposed)             
throw new ObjectDisposedException("Resource was disposed.");          
// Show the number of bytes.         
int numBytes = (int) _resource.Length;         
Console.WriteLine("Number of bytes: {0}", numBytes.ToString());    
 }       
public void Dispose()      
{        
 Dispose(true);          
// Use SupressFinalize in case a subclass        
 // of this type implements a finalizer.         
GC.SuppressFinalize(this);           
}     
 protected virtual void Dispose(bool disposing)     
{        
 // If you need thread safety, use a lock around these          
// operations, as well as in your methods that use the resource.         
if (!_disposed)         
{             
if (disposing)
 {                 
if (_resource != null)                     
_resource.Dispose();                     
Console.WriteLine("Object disposed.");            
 }             
 // Indicate that the instance has been disposed.             
_resource = null;             
_disposed = true;            
}     
} 
} 

Microsoft suggests :
You should prevent users of your application from calling an object's Finalize method directly by
limiting its scope to protected. In addition, you are strongly discouraged from calling a
Finalize method for a class other than your base class directly from your application's code. To
properly dispose of unmanaged resources, it is recommended that you implement a
public Dispose or Close method that executes the necessary cleanup code for the object. The
IDisposable interface provides the Dispose method for resource classes that implement the
interface. Because it is public, users of your application can call the Dispose method directly to
free memory used by unmanaged resources. When you properly implement a Dispose
method, the Finalize method becomes a safeguard to clean up resources in the event that the
Dispose method is not called.
G. Weak References: (Advisable to use at very critical situation of memory management)
Source: MSDN & Craig Gemmill's Blog
The general thinking is that you only use Weak References when you are dealing with large chunks
of data that can be easily recreated, such as multimedia content. While a weak reference
can be an appealing option for automatic memory management, it should only be used if a caching
solution doesn't work.
Here is an example where Weak References would be helpful:
You have a form that displays a huge picture as the background. Now let’s say that you show another
window that obstructs the view of the original window and the picture is not seen
at all. Why have the picture stored in memory if it’s not being used? If you create a pointer to the
picture using a Weak Reference, and another part of your program needs to use a
significant amount of memory, the Garbage Collector can now release the memory that was being
used by the picture and use it for the active operation.
When you return to the main screen, you can simply reload the image from disk like nothing happened.
Here is some code to help:
Public Class Form1
Const IMAGE_FILENAME As String = "C:\MyPicture.jpg"
Private _imgPTR As New WeakReference(Image.FromFile(IMAGE_FILENAME), False)
Protected Overrides Sub OnPaint(ByVal e As System.Windows.Forms.PaintEventArgs)
If Not _imgPTR.IsAlive Then
_imgPTR.Target = Image.FromFile(IMAGE_FILENAME)
End If
e.Graphics.DrawImage(DirectCast(_imgPTR.Target, Image), Me.ClientRectangle)
MyBase.OnPaint(e)
End Sub
Private Sub Form1_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Click
DirectCast(_imgPTR.Target, Image).Dispose()
GC.Collect()
End Sub
End Class
H. Induced Collection: [Describes how to reclaim objects immediately or at the next optimal time.]
You can use the GCCollect(Int32, GCCollectionMode) method overload that takes a GCCollectionMode
value to specify
the behavior for a forced collection, as described in the following table.
Member Description
Default() Uses the setting designated as the default garbage collection
configuration of the running version of the .NET Framework.
Forced() Forces garbage collection to occur immediately. This is equivalent to calling GC..::.Collect().
Optimized() Enables the garbage collector to determine whether the current time is optimal to reclaim objects.
The garbage collector could determine that a collection would not be productive enough to be justified, in which
case it will return without reclaiming objects.
I. Latency Modes
To reclaim objects, the garbage collector must stop all of an application's executing threads. In some situations,
such as when an application retrieves data or displays content, a full
garbage collection can occur at a critical time and impede performance. You can adjust the intrusiveness of the
garbage collector by setting the LatencyMode() property to one of the
GCLatencyMode values.
Latency refers to the time that the garbage collector intrudes in your application. During low latency periods the
garbage collector is more conservative, and less intrusive, in
reclaiming objects. Generation 2 collections occur less frequently, which causes the application working set to grow
over time. As a result, it is recommended that you use the
LowLatency() mode only for the short period of time when it is needed. Otherwise, if the system is under memory
pressure, the garbage collector will trigger a collection, which can briefly
pause the application and disrupt a time-critical operation.
You should use the latency mode with applications that include a block of code that runs over a brief period of
time and must run with minimal interruptions from the runtime.Although
the LowLatency() mode is designed to be used in scenarios where there are some time constraints, it is not intended
to be a solution for scenarios where there are strict real-time
constraints.
Latency mode Application scenarios
Batch() For applications that have no UI or server-side operations.
Interactive() For most applications that have a UI.
LowLatency() For applications that have short-term, time-sensitive operations when
interruptions from the garbage collector could be disruptive. For
example, applications that do animation rendering or data acquisition
functions.
If the LatencyMode() property is not specified, the default mode is concurrent workstation garbage collection. The mode
is dependent on the value of two runtime configuration settings:
  • If enabled, this setting specifies that the common language runtime runs workstation garbage collection on a
    separate thread to support concurrent operations. This setting is enabled by default.
  • If enabled, this setting specifies that the common language runtime runs server garbage collection; otherwise, it
    runs workstation garbage collection. You can enable server garbage collection only on computers with two or more
    processors. It is not enabled by default.
    If this setting is enabled, "> is automatically disabled.
    The default values for GCLatencyMode are as follows:
  • Interactive when "> is enabled and "> is disabled.
  • Batch when "> is disabled, or when both "> and "> are enabled.
Note:
Concurrent garbage collection is not supported in applications running the WOW64 x86 emulator on 64-bit
systems that implement the Intel
Itanium architecture (formerly called IA-64).
J. Optimization for Share Web Hosting [This setting is recommended only for shared Web hosting scenarios.]
If you are the administrator for a server that is shared by hosting several small Web sites, you can optimize
performance and increase site capacity by adding the following
gcTrimCommitOnLowMemory setting to the runtime node in the Aspnet.config file in the .NET Framework directory:
Because the garbage collector retains memory for future allocations, its committed space can be more than
what is strictly needed. You can reduce this space to accommodate times
when there is a heavy load on system memory. Reducing this committed space improves performance and
expands the capacity to host more sites.
When the gcTrimCommitOnLowMemory setting is enabled, the garbage collector evaluates the system memory
load and enters a trimming mode when the load reaches 90%. It maintains
the trimming mode until the load drops under 85%.
When conditions permit, the garbage collector can decide that the gcTrimCommitOnLowMemory setting will
not help the current application and ignore it.
Reference:
Weak Ref.
Induced Collection
Latency Modes
Optimization for Shared Web Hosting


This page is powered by Blogger. Isn't yours?

Subscribe to Posts [Atom]

Watch the latest videos on YouTube.com