PRB: Premature Garbage Collection of Object Reference (309327)



The information in this article applies to:

  • Microsoft Common Language Runtime (included with the .NET Framework) 1.0

This article was previously published under Q309327

SYMPTOMS

If a managed object contains a reference to an unmanaged resource, and the object has a finalizer method to release the unmanaged resource, make sure that the object is alive until all platform invoke (PInvoke) calls that use the unmanaged resource have completed. Otherwise, Garbage Collection may collect the object, which causes the object's finalizer to release the unmanaged resource. Any later references to that resource may result in an Access Violation or memory corruption.

RESOLUTION

The resolution to this problem depends on the nature of the unmanaged resource. For the purpose of this article, unmanaged resources fall into two catagories:
  • Resources that are handles to operating system objects.
  • Resources that are not handles to operating system objects.
When you use Interop Services, there are two mechanisms for interoperating with unmanaged code. One is the Platform Invoke Service, which allows managed code to call unmanaged functions that are implemented in dynamic-link libraries (DLLs). The other mechanism is COM Interop, which is a bi-directional service that bridges between the .NET Framework and COM components.

PInvoke and Handles to Operating System Objects

When you work with handles to operating system objects, such as window handles and device contexts, use the HandleRef structure to wrap the resources. Platform Interop Services works with the HandleRef structure.

Note In the following COM Interop example, this problem is resolved by making calls to the KeepAlive method of the Garbage Collector. Although this will work with Platform Invoke calls, HandleRef is the recommended approach.
Option Strict On
Option Explicit On 

Imports System.Runtime.InteropServices

Module Module1

        Private Declare Function GetGraphicsMode Lib "gdi32" Alias "GetGraphicsMode" _
              (ByVal hdc As HandleRef) As Integer
        Private Declare Function GetDC Lib "user32" _
              (ByVal hwnd As IntPtr) As IntPtr
        Private Declare Function ReleaseDC Lib "user32" _
              (ByVal hwnd As IntPtr, ByVal hdc As HandleRef) As Integer


    Class Test
        Public hdcscreen As HandleRef

        Public Sub New()
            hdcscreen = New HandleRef(Me, GetDC(IntPtr.Zero))
        End Sub

        Protected Overrides Sub Finalize()
            Dim ret As Integer
            ret = ReleaseDC(IntPtr.Zero, hdcscreen)
            MyBase.Finalize()
        End Sub
    End Class


    Sub Main()
        Dim mvb As New Test()
        Dim GrMode As Integer
        GrMode = GetGraphicsMode(mvb.hdcscreen)
        Console.Write(GrMode.ToString)
    End Sub


End Module
				

COM Interop and Other Types of Resources

For resources where HandleRef is not applicable, such as a database connection, use GC.KeepAlive to maintain an object's existence, as in the following sample code:
Imports System
Imports System.Reflection

Module MyModule
Sub Main()

  Dim conn = Activator.CreateInstance(Type.GetTypeFromProgId("ADODB.Connection"))
  conn.Open _ 
    ("Provider=SQLOLEDB.1;Data Source=(local);Integrated Security=SSPI;Initial Catalog=pubs")
  Dim rs = conn.Execute("SELECT * FROM employee")

  Dim id
  If Not rs.EOF Then
     id = rs("emp_id").Value
     Console.WriteLine(id)
  Else
     Console.WriteLine("Empty Recordset")	
  End If

  GC.KeepAlive(conn)
  GC.KeepAlive(rs)
  GC.KeepAlive(id)

End Sub
End Module
				
For more about automatic memory management, visit the following Microsoft Developer Network Web site:

Modification Type:MinorLast Reviewed:5/2/2003
Keywords:kbnofix kbprb kbreadme kbUpgrade KB309327