Article Options
Premium Sponsor
Premium Sponsor

 »  Home  »  .NET Framework  »  Manage Unmanaged Resources and Memory With VB.NET
Manage Unmanaged Resources and Memory With VB.NET
by Mike McIntyre | Published  06/15/2003 | .NET Framework | Rating:
Mike McIntyre

I am a system architect, developer, and project manager for aZ Software Developers, LLP.

I feel very lucky because my work at aZ Software Developers allows me the time to be an active mentor, trainer, and coach in the Microsoft .NET technical community.

DevCity is my favorite community site. Click to see my DevCity profile -> Mike McIntyre

 

 

View all articles by Mike McIntyre...
Manage Unmanaged Resources and Memory With VB.NET

Applies To: Microsoft.NET Framework 1.0 and Visual Studio.Net 2002

The .NET Framework's Common Language Runtime (CLR), through its Garbage Collector (GC), provides memory management services your VB.NET application. In three situations your program must do some housekeeping before the GC can do its job.

1. The CLR does not release unmanaged resources which your program objects have used. Your code must explicitly release unmanaged resources by calling the Dispose method on objects which have used unmanaged resources.

2. The CLR will not clear an object from memory if the object is still referenced by your running program, even though it is no longer needed by the running program. You must ensure that when your program is finished with an object, the variable(s) in the running program which reference the object 1) have been destroyed automatically because the variable(s) went out of scope or 2) have been assigned a value of NOTHING so they no longer hold a reference to the object.

3. Under some circumstances, the CLR will not remove large unreferenced objects from memory without help from your code. This a fairly obscure issue, and it is not covered here.

Releasing Unmanaged Resources Used By An Object vs Dereferencing An Object

Releasing unmanaged resources used by an object is different than dereferencing a .NET object so it can be destroyed by the Common Language Runtime (CLR) garbage collector (GC).

If your program dereferences an object which is using unmanaged resources - without first releasing the object's unmanaged resources - the object will be destroyed by the GC but its unmanaged resources will be left active. Active unmanaged resources permanently tie up some memory (memory leak) and lock resources which may be needed by your program or other programs running on the same computer. The result ranges from a slight decrease in program performance to a program crash.

Dereferencing An Object

A dereferenced object is an object which is no longer referenced by a running program. An object that has been dereferenced is destroyed by the GC to free up memory for other program needs.

Program reference type variables can hold NOTHING or a reference (memory address) of an object in memory. As long as at least one variable in the running program still contains a reference to an object in memory, the object will not be destroyed by the GC.

An object is dereferenced in two ways.

1. The program variables which reference the object go out of scope and are automatically destroyed e.g. variables declared within a method are destroyed after the method call is complete.

2. Program code assigns NOTHING to the variable(s) that reference the object.
    ' Dereference a DataSet object by setting
    ' the value of the variable that references it to NOTHING
    myDataSet = NOTHING

Releasing an Object's Unmanaged Resources

This is an entirely different process than dereferencing an object.

If an object uses unmanaged resources, the program must call the object's Dispose method to release the unmanaged resources after the program has finished using the object.

Release unmanaged resources before the object that has used them is dereferenced. If the object is dereferenced before you have called the Dispose method on the object, the object will be destroyed by the GC but its unmanaged resources will remain active. At this point the unmanaged resources will only be released when the program terminates.

On the following pages is some sample code. After the code you will find an analysis of the code.

BuildCustomerCollection Class Version 1 - Bad Code

Public Class BuildCustomerCollection

    Public Function GetCustomers() As ArrayList
        ' Declare a variable named customerList
        '   of type ArrayList.
        Dim customerList As ArrayList

        ' Declare a variable named sqlConnection
        '   of type SqlConnection.  Instantiate and assign
        '   an SqlConnection object to sqlConnection.
        ' A SqlConnection object uses a database connection.
        ' A database connection is an unmanaged resource.
        Dim sqlConnection As New _
        SqlClient.SqlConnection("Provider=SQLOLEDB.1;etc.")

        ' Open a connection to the database.
        sqlConnection.Open()

        ' Code that fills the customerList goes here.

        ' Close the connection to the database.
        ' NOTE: Closing a connection does not release
        '       a connection resource.
        sqlConnection.Close()

        ' Return an ArrayList filled with Customers
        ' to the method which called the GetCustomers
        ' method.
        Return customerList
    End Function
End Class

BuildCustomerCollection Class Version 2 - Good Code

Public Class BuildCustomerCollection

    Public Function GetCustomers() As ArrayList
        ' Declare a variable named customerList
        '   of type ArrayList.
        Dim customerList As ArrayList

        ' Declare a variable named sqlConnection
        '   of type SqlConnection.  Instantiate and assign
        '   an SqlConnection object to sqlConnection.
        ' A SqlConnection object uses a database connection.
        ' A database connection is an unmanaged resource.
        Dim sqlConnection As New _
        SqlClient.SqlConnection("Provider=SQLOLEDB.1;etc.")

        ' Open a connection to the database.
        sqlConnection.Open()

        ' Code that fills the customerList goes here.

        ' Close the connection to the database.
        ' NOTE: Closing a connection does not release
        '       a connection resource.
        sqlConnection.Close()

        ' Dispose the SqlConnection object so that it
        ' releases its unmananged database connection
        ' resource.
        sqlConnection.Dispose()

        ' Return an ArrayList filled with Customers
        ' to the method which called the GetCustomers
        ' method.
        Return customerList
    End Function
End Class

GetSomeData Method

Here is an example method which uses a BuildCustomersCollection object.

Public Sub GetSomeData()
    ' Declare a variable named customers
    ' of type ArrayList.
    Dim customers As ArrayList

    ' Delcare a variable named builder,
    '    of type BuildCustomerCollection.
    ' Use the New keyword to instantiate (create)
    '    a BuildCustomerCollection object in memory.
    ' Assign the address of the new object
    '    to the builder variable.
    ' The Builder variable now references
    '    a BuildCustomerCollection object.
    Dim builder As New BuildCustomerCollection()

    ' Call the BuildCustomerCollection object's
    '    GetCustomers method.
    ' Assign the address of the ArrayList oject
    '    it creates to the customers variable.
    customers = builder.GetCustomers

    ' The builder variable will go out of
    '   scope and will be automatically destroyed
    '   when the program exits this method.
    ' Because the builder variable is the only 
    '   program variable which refererenced the
    '   BuildCustomerCollection object created in
    '   this method, the object will be
    '   dereferenced by the destruction of
    '   the builder variable.
    ' The GC will destroy the object to reclaim
    '  its memory for other uses.
    ' In this case, this code:
    '     builder = NOTHING
    ' is not required to dereference the object.
End Sub

Analysis

Both versions of the BuildCustomerCollection Class above use a .NET SqlConnection object. A SqlConnection object uses unmanaged resources.

Version 1 of the BuildCustomerCollection Class is bad because it does not call Dispose on its SqlConnection object's unmanaged resources when it has finished using the SqlConnection object. Therefore the unmanaged resources used by the SqlConnection object are not released when the SqlConnection object is destroyed by the garbage collector.

Version 2 of the BuildCustomerCollection Class is good because it calls Dispose on its SqlConnection object which releases the object's unmanaged resources before the object is dereferenced and then destroyed by the garbage collection. The result: the object's unmanaged resources are released and the object is destroyed.

First imagine program which uses the BuildCustomerCollection Class Version 1 and the GetSomeData Method code.

The program does NOT call the SqlConnection object's Dispose method.

In the GetSomeData method, a BuildCustomersCollection object is instantiated, assigned to the builder variable, and the builder variable is used to call the BuildCustomersCollection.GetCustomers method. When the method is exited, the builder variable goes out of scope and is destroyed which dereferences the BuildCustomersCollection object.

This leaves the BuildCustomersCollection object in memory without any reference to it from the running program. The GC will remove it from memory.

At this point the object no longer exists in memory. But ... the BuildCustomersCollection unmanaged resources were not released. The object's unmanaged resources - not the object itself - are now left active and orphaned with no way for the program to release them. This is a bad thing!

Now imagine program which uses the BuildCustomerCollection Class Version 2 and the GetSomeData Method code.

The program does call the SqlConnection object's Dispose method.

In the GetSomeData method, a BuildCustomersCollection object is instantiated, assigned to the builder variable, and the builder variable is used to call the BuildCustomersCollection.GetCustomers method. When the method is exited, the builder variable goes out of scope and is destroyed which dereferences the BuildCustomersCollection object.

This leaves the BuildCustomersCollection object in memory without any reference to it from the running program. The GC will remove it from memory.

At this point the object and its unmanaged resources are gone. This is a good thing!

Your Responsibility

If you use any .NET object which uses unmanaged resources you are responsible to see that the unmanaged resources are released after using the object. Calling the Dispose method on such an object releases the unmanaged resources the object has used.

There is one exception. In some cases Visual Studio adds code to Dispose objects so you don't have to. For example, look for the code below in a Form that has been created with the Form designer code generated by theForm designer.

    'Form overrides dispose to clean up the component list.
    Protected Overloads Overrides Sub Dispose(ByVal disposing As Boolean)
        If disposing Then
            If Not (components Is NothingThen
                components.Dispose()
            End If
        End If
        MyBase.Dispose(disposing)
    End Sub

This method is called when a Form is closed. It disposes the objects contained by the Form thus releasing the unmanaged resources they used.

If Visual Studio does not generate code to Dispose your objects for you, you must Dispose them yourself.

Which Objects Should Be Disposed?

You can determine if you need to dispose an object by using Intellisense. As a demonstration, use the code editor to declare a SqlConnection variable.

    Dim sqlConnection As New SqlClient.SqlConnection("Provider=SQLOLEDB.1;etc.")

Now type the variable's name followed by a period. If you see Dispose in the Intellisense list which pops up you must call Dispose on the the SqlConnection object when you have finished using it and before it is dereferenced. You use Intellisense to check for Dispose method(s) on any object.

    sqlConnection.Dispose()

You can also determine if you need to dispose an object by reading the object's Type Members help topic in .NET help. Every type you can use in from the .Net Framework has a matching Type Members help topic that documents the type's members.

To demonstrate, search .NET help using this search string: SqlConnection Members. Open the SqlConnection Members help topic and find its Public Methods Section. If Dispose is listed as one of the Public Methods you must call Dispose on a SqlConnection object when you have finished using it and before it is dereferenced.

NOTE: Don't be lead off track by .NET help topics. If Dispose is available for an object in Intellisense or is shown as a member of a Type's Public Methods- you must use it.

You may find documentation which says don't call Dispose directly. This is can be the case when you are viewing information about a base class from which the class you actually used is derived. If the class you are using implements a Dispose method, use it.

You may find a listing called Overloaded Dispose methods in the documentation for the class you are using.

Some of the Overloaded Dispose methods listed may include a warning not to use certain a particular Overloaded Dispose method. You may use the ones which do not include warnings.

Here is an example - the overloaded Dispose methods of the SqlConnection class.

Overload List

Releases all resources used by this Brush object.

Overloads NotOverridable Public Sub Dispose() Implements IDisposable.Dispose

This member supports the .NET Framework infrastructure and is not intended to be used directly from your code.

Overloads Overridable Protected Sub Dispose(Boolean)

Click the Dispose link shown in the SqlConnection Members help topic's Public Methods section. A new help topic will open and it will show the Overloaded Methods of the Dispose method. Shown immediately above is a portion of the OverLoad List help topic.

The first Overloaded Dispose method is highlighted in yellow above.

Dispose()

It does not include a warning, not to use it; this is the one to use.

The second is highlighted in blue above.

Dispose(Boolean)

It is includes by a warning. Do not use it.

Optimize Garbage Collection

Your code can optimize garbage collection through the proper use of disposing and dereferencing objects.

Dereference an object which does not use unmanaged resources as soon as your program no longer needs it.

Call Dispose on an object which uses unmanaged resources as soon as your program no longer needs it. Immediately thereafter dereference the object.

Most types that use unmanaged resources implement a Dispose Pattern. A Type which implements the Dispose Pattern is a Type which implements (A), (B), and (C) below.

A. A Method That Releases Unmanaged Resource(s)

This method releases unmanaged resources used by objects which have not already been released by program code before this method is called.

B. Dispose Method

This method calls the method that releases unmanaged resources (A).

If the call succeeds, the method tells the GC to suppress (not run) the object's Finalize method (C).

The only way this method is called is if your code calls this method.

C. Finalize Method

If the Dispose method (B) was successful, the GC will not run this method.

If the Dispose method (B) failed - or the programmer forgets to call the Dispose method, the GC is forced to call the method that releases unmanaged resources (A).

Think of this method as insurance. If (B) fails to release an object's unmanaged resources, the GC will call this method later in one last attempt to free up the object's resources before it destroys the object.

Like all insurance, there is a cost involved.

If (B) is successful, memory is reclaimed sooner and garbage collection is quicker. The object is destroyed the very next time the GC destroys dereferenced objects.

If (B) is unsuccessful - or the programmer forgets to call the Dispose method - the GC must handle the object differently, in a process that takes more time and processor cycles.

The GC does not remove objects which need to be finalized the very next time it performs a garbage collection. Instead, on the next garbage collection, the GC starts a process which eventually leads to the object being destroyed.

The GC starts the process by adding a reference to the object to a Finalization queue.

The CLR processes the objects referenced in the queue. By reference it calls the object's Finalization method and then removes the object's reference from the queue. This makes the object eligible for destruction by the GC.

The object MAY be destroyed the next time the GC destroys objects, but not necessarily. The object has gotten older. The GC destroys the youngest eligible objects first, and only enough to meet a threshold of available memory. This means it may be some time before the GC needs to destroy the older object to meet the minimum memory threshold.

One final note, if the object waiting to be finalized refers to other objects ready for garbage collection which does NOT need to be finalized; those objects are held back too.

The bottom line: Call Dispose on objects which use unmanaged resources, as soon as your program no longer needs them and ensure the object is dereferenced immediately thereafter.

Additional Information About Unmanaged Resources

Program Resources

Every computer program uses resources. Resources are things which support and help the program to do its job. Here are some examples of resources a program may use:

  • Memory
  • File
  • Windows OS
  • Integer
  • Button
  • OleDbConnection
  • DataSet
  • Pen
  • Screen Area
  • String

At runtime, every object you use in your program will consumes one or more resource(s). For example, if your VB.NET program code declares a variable of type integer, at runtime the Common Language Runtime (CLR) will allocate a resource (application memory) to contain the variable and its value.

.NET Managed Resources vs Unmanaged Resources

A .NET program can use both managed and unmanaged resources.

A managed resource is a resource which is fully contained within the .Net application's memory. Examples:

  • Integer
  • String

An unmanaged resource is a resource which is provided to a .NET object by a source outside the CLR. Here are some examples.

  • File
  • Windows OS
  • Button
  • OleDbConnection
  • DataSet
  • Pen
  • Screen Area
How would you rate the quality of this article?
1 2 3 4 5
Poor Excellent
Tell us why you rated this way (optional):

Article Rating
The average rating is: No-one else has rated this article yet.

Article rating:2.23367697594505 out of 5
 291 people have rated this page
Article Score77536
Sponsored Links