0 out of 3 rated this helpful - Rate this topic

GC.KeepAlive Method

References the specified object, which makes it ineligible for garbage collection from the start of the current routine to the point where this method is called.

Namespace:  System
Assembly:  mscorlib (in mscorlib.dll)
public static void KeepAlive(
	Object obj
)

Parameters

obj
Type: System.Object
The object to reference.

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.

The following code example creates an object at the beginning of its Main method and does not refer to the object again until the end, when the KeepAlive method is called. The object persists for the 30-second duration of the Main method, despite calls to the Collect and WaitForPendingFinalizers methods.


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();
    }
}


.NET Framework

Supported in: 4, 3.5, 3.0, 2.0, 1.1, 1.0

.NET Framework Client Profile

Supported in: 4, 3.5 SP1

Portable Class Library

Supported in: Portable Class Library

Windows 7, Windows Vista SP1 or later, Windows XP SP3, Windows XP SP2 x64 Edition, Windows Server 2008 (Server Core not supported), Windows Server 2008 R2 (Server Core supported with SP1 or later), Windows Server 2003 SP2

The .NET Framework does not support all versions of every platform. For a list of the supported versions, see .NET Framework System Requirements.
Did you find this helpful?
(1500 characters remaining)
Community Content Add
Annotations FAQ
Bad sample code
$0The example does not properly illustrate GC.KeepAlive behavior! The function at the end could be anything and hr would still be kept alive for the lifetime of the function since that line references the object. The KeepAlive line after the Collect cannot change the behavior of the Collect. Furthermore, it is passed to SetConsoleCtrlHandler which most people would assume is going to save a reference to it as well. Does anyone actually review these code samples for accuracy or usefulness? Here is a correct example:$0 $0 $0 $0public static void Main() {     // Use interop to set a console control handler.     MyWin32.HandlerRoutine hr = new MyWin32.HandlerRoutine(Handler);     MyWin32.SetConsoleCtrlHandler(hr, true);     // 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.     // This is necessary because SetConsoleCtrlHandler is a WINAPI which     // does not keep a reference to the handler that GC will see.     GC.KeepAlive(hr);     hr = null;     // The object hr is not referred to again.     // THIS STATEMENT WAS FALSE IN THE ORIGINAL EXAMPLE BUT IS NOW TRUE     // BECAUSE WE DELETED OUR REFERENCE BY ASSIGNING NULL TO IT ABOVE.     // 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!");     Console.Read();     }
$0 $0
Edit:
The original sample code is fine, but it must be run outside of the debugger to exhibit the expected crash (Visual Studio default key-mapping: Ctrl+F5). The garbage collector behavior is different when running under debug conditions, and both samples will function then.

This 'fixed' sample demonstrates how not to use GC.KeepAlive. Because the call to KeepAlive is made before the range of instructions where the object must be available (see the documentation remarks), the object is garbage collected and the application fails as expected. The line setting the reference to null has no affect on the failure, but does prevent the use of KeepAlive at the correct location.

$0 $0

$0 $0 $0