Help topic for the GC.KeepAlive method is not complete (821779)



The information in this article applies to:

  • Microsoft Visual Studio .NET (2003), Enterprise Architect Edition
  • Microsoft Visual Studio .NET (2003), Enterprise Developer Edition
  • Microsoft Visual Studio .NET (2003), Academic Edition
  • Microsoft Visual Studio .NET (2002), Professional Edition
  • Microsoft Visual Studio .NET (2002), Enterprise Architect Edition
  • Microsoft Visual Studio .NET (2002), Enterprise Developer Edition
  • Microsoft Visual Studio .NET (2002), Academic Edition

SUMMARY

In the Microsoft .NET Framework Class Library documentation, the Help topic for the GC.KeepAlive method is not complete. For more information, visit the following Microsoft Web site:

MORE INFORMATION

The existing documentation should also include the following information:

You can also use the KeepAlive method to prevent a finalizer from being started prematurely. The following scenario describes the problem that may occur if you do not prevent a finalizer from being started prematurely:
  1. You have an object that is a member of a class. You work with this object in the finalizer of the class, and then you instantiate a different object of the class.
  2. You try to gain access to an object that is a member of the newly instantiated object.
In this scenario, you may notice that the newly instantiated object is prematurely finalized. Therefore, the object that is a member of the newly instantiated object is manipulated in the finalizer. This behavior may cause unexpected results.

To prevent the finalizer from being started prematurely, start the KeepAlive method and use a reference to the newly instantiated object as the parameter. Start the KeepAlive method in the method or property procedure where you gain access to the object that is a member of the newly instantiated object. To do this, use the following sample code:

Microsoft Visual Basic .NET sample code

Option Strict On

Imports System

Namespace KeepAliveDemo
   Class Class1
      ' Object that is a member of a class.
      Private MyPrivateArray As Integer()

      Public ReadOnly Property MyArray() As Integer()
         Get
            Return CType(MyPrivateArray.Clone(), Integer())
         End Get
      End Property

      ' Constructor.
      Public Sub New()
         MyPrivateArray = New Integer(5) {}
         MyPrivateArray(0) = 10
      End Sub

      ' Finalizer.
      Protected Overrides Sub Finalize()
         MyBase.Finalize()

         If Not (MyPrivateArray Is Nothing) Then
            ' Modify the object that is a member of this class.
            Array.Clear(MyPrivateArray, 0, MyPrivateArray.Length)
         End If
      End Sub

   End Class

   Class Class2
      Shared Sub Main()
         Dim Continue As Boolean = True

         While (Continue)
            ' Instantiate an object of type Class1.
            Dim Test As New Class1

            If Test.MyArray(0) = 10 Then
               Console.WriteLine("Finalizer not invoked prematurely")
            Else
               Console.WriteLine("Finalizer invoked prematurely. Press ENTER to quit.")
               Console.ReadLine()
               Continue = False
            End If

            ' If the following statement is missing, the finalizer may be invoked prematurely.
            GC.KeepAlive(Test)
         End While

      End Sub

   End Class

End Namespace

Microsoft Visual C# .NET sample code

using System;

namespace KeepAliveDemo
{
	class Class1
	{
		// Object that is a member of a class.
		private int[] MyPrivateArray;

		public int[] MyArray
		{
			get
			{
				return (int[]) MyPrivateArray.Clone();
			}
		}

		// Constructor.
		public Class1()
		{
			MyPrivateArray = new int[5];
			MyPrivateArray[0] = 10;
		}

		// Finalizer.
		~Class1()
		{
			if (MyPrivateArray != null)
				// Modify the object that is a member of this class.
				Array.Clear(MyPrivateArray, 0, MyPrivateArray.Length);
		}
	}

	class Class2
	{
		static void Main(string[] args)
		{
			bool Continue = true;

			while(Continue)
			{
				// Instantiate an object of type Class1.
				Class1 Test = new Class1();

				if (Test.MyArray[0] == 10)
					Console.WriteLine("Finalizer not invoked prematurely");
				else
				{
					Console.WriteLine("Finalizer invoked prematurely; press ENTER to quit");
					Console.ReadLine();
					Continue = false;
				}

				// If the following statement is missing, the finalizer may be invoked prematurely.
				GC.KeepAlive(Test);
			}
		}
	}
}
In this example, MyPrivateArray is a member of Class1. MyPrivateArray is manipulated in the finalizer of Class1. Test is an object of type Class1. Test is instantiated in the Main method of Class2, and the corresponding MyPrivateArray member is accessed by using the MyArray property. If you do not use GC.KeepAlive(Test) when you run this sample application, you may receive the following custom message:Finalizer invoked prematurely; press ENTER to quitThis message indicates that Test was prematurely finalized.

Also, use the KeepAlive method when you work with member data in the Dispose method of classes that inherit from the IDisposable interface. The implementation details are similar to the previous example.

Microsoft recommends that you always use write code similar to the example that appears in this article when you work with object references (other than a reference to the current object) in finalizers or in Dispose methods.

REFERENCES

For more information, visit the following Microsoft Web sites: For more information, click the following article number to view the article in the Microsoft Knowledge Base:

309327 PRB: Premature Garbage Collection of object reference


Modification Type:MinorLast Reviewed:3/7/2006
Keywords:kbvs2005doesnotapply kbvs2005swept kbvs2002sp1sweep kbDevStudio kbMemory kbDocs kbGarbageCollect kbConsole kbProgramming kbSample kbdocfix kbdocerr kbBug KB821779 kbAudDeveloper