Article Options
Recently Viewed
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:4.17000000000002 out of 5
 100 people have rated this page
Article Score60355
Comments    Submit Comment

Comment #1  (Posted by kamau on 06/18/2003)

Excellent article. I've read a couple of books on .net and the GC but I always got confused. You sqlconnection example has really helped! I always wondered what the difference between = Nothing and .dispose were since they all sounded like they did the same thing. Plus throwing in the fact that the gc doesn't actually dispose of objects immediately just made matters worse. Now it's clear!
 
Comment #2  (Posted by chandrakant on 06/18/2003)

HI ,
It is really very helpfull document. Good one
 
Comment #3  (Posted by juan on 06/26/2003)

I don't agree with the way you dispose de SqlConnection object. As far as I know, calling the close method is enough since the connection being closed is allocated back into the pool of connections that the sql server provider manages... if you call Dispose on a SqlConnection object, you force the object to be destroyed and don't benefit from connection pooling on that object.... Is it right? I wait for your answer since disposing objects is one of the main issues of good .net programming, and now I am in doubt if I am doing it the right way...
 
Comment #4  (Posted by Mike McIntyre on 06/26/2003)

Juan,

You are correct. Until the point you have finished using the connection you can call Open and Close on the connection - and connection pooling will do its job.

But my article is about disposing objects when the program no longer needs them - whether that is at the end of a method call, scoped to class level or even higher. The example shows a single call to a method that uses a SqlConnection once. In this case I could have called Close then Dispose or just Dispose which closes and disposes the SqlConnection object.

Mike
 
Comment #5  (Posted by karl on 06/30/2003)

Yes, the close/dispose bit is pretty much wrong. There has been numerous discussions about this and the general consensus (as far as I can tell), is that they pretty much do the same. There is even some discussion that .dispose() removes the connection from the connection pool, which would be a great reason to call close() instead of dispose().

I'd recommend that anyone reads http://www.asp.net/Forums/ShowPost.aspx?tabindex=1&PostID=247947 for more details on this issue...instead of assuming close() is the wrong way to do it.
 
Comment #6  (Posted by Mike McIntyre on 06/30/2003)

Karl,

That thread you mention is typical of serveral long threads on the internet that try to come to a consensus about close vs dispose on a connection. It has pros and cons both ways but fails to recognize that Close is a necessary method for connections and dispose is a method necessary for any object which uses unmanaged resources. Each has its place when using connection objects.

Here are some facts which can be proven with any good diagnostic tool:

A. Close - Closes a connection, it does not dispose the connection.
B. Dispose - Closes and Disposes a connection.
C. Leaving any object referenced prevents it from being GCd.
D. Dereferencing a connection object without disposing it first leaves the connection object's UNMANAGED resrouces in limbo and untouchable by the GC - after the object itself is gone.
E. Any object which uses UNMANAGED resources (which is the case with a connection) must be disposed to release those resources.

Here is some good advice from the thread you referenced which is mirrored in my article:

"if you plan to reuse that same object later in the page or execution, then yes. .Close() is enough. However, if it's the end of that thread.. destroy the object properly."

At aZ Software we discovered the difference two years ago when an very large enterprise application started leaking memory when put under heavy testing by 100 end users. We were exclusively using Close on the connections used in method calls in web pages. Within an hour we had heavy complaints and approx 75 minutes in the application crashed. Once we implemented the proper use of Close with Dispose each time a connection was no longer needed, the memory leak went away.

The bottome line - Close connections when you know your application will Open and use the connection again - but when you are finished using the connection object dispose it to release unmanaged resources and make sure the object is dereferenced. The example in the article shows how to Dispose an object that is not longer needed.

Here is another article you may find helpful. It is not specific to connections but it does empasize the importance of Disposing ANY object that uses unmanaged resources.

http://www.fawcette.com/vsm/2002_08/online/santanna/default_pf.asp

 
Comment #7  (Posted by Mike McIntyre on 06/30/2003)

For more details about the SQL Connection object and connection pooling search .Net Help with these search strings:

SqlConnection Class
SqlConnection Members
SqlConnection.Close Method
Connection Pooling for the SQL Server .NET Data Provider
 
Comment #8  (Posted by Mahesh on 12/31/2003)

Hi there My application which is just 300Kbs in size EATs 18-MB of Ram I have already optimized My Code but doesnt help I tried the Compiler Optimization too no use. Can you please help me !! I went through your Article very well written But Frankly speaking I have some doubts like do we have to call every Objects dispose to free the memory ? even strings ? and string arrays ? Integers ,etc ??
Thanks for such a nice article
 
Comment #9  (Posted by Mike McIntyre on 12/31/2003)

Thank you, Mahesh.

You should call dispose on those objects which have a dispose method. Managed code objects such as string and integer do not have dispose methods. See the guidelines in the article to learn how to determine if a class has a Dispose method.

Your application is probably holding onto less memory than you think - that is if you are judging it stricly by what you see in the Task Manager or using .NET instrumentation. I published an article in the DevCity newsletter a few months ago titled "The Memory Mystery" which explains how to judge your application's memory useage correctly. If you send your email address to me at mikemc@getdotnetcode.com I will email you a copy of the article.
 
Comment #10  (Posted by asitaaa on 05/04/2004)

help ! help !! help !!!
I have a control on which I have a picture box and I draw it from a Bitmap (a TIFF file). I then determine how many pages (frames) the TIFF file has and create each frame as a file in a temp directory. 0.tif, 1.tif, 2.tif, etc.

If I change my query parameters, I get a new TIFF file. At this point I want to delete the old file(s) so that I can re-create my TIFF files.

So I have the following code:


Code:

curF = 0
For z = 0 To (totFrame - 1)
If File.Exists(strPath & curF & ".tif") Then
File.Delete(strPath & curF & ".tif")
End If
b2Map.SelectActiveFrame(objDimension, curF)
b2Map.Save(strPath & curF & ".tif", Imaging.ImageFormat.Tiff)
curF = curF + 1
Next




When I run my program, the first time it runs smoothly. But when I clear my query parameters it tries to delete the TIFF files and it gives the following error:

An unhandled exception of type 'System.IO.IOException' occurred in mscorlib.dll

Additional information: The process cannot access the file "c:\temp\0.tif" because it is being used by another process.

It bombs out on File.Delete line. I also tried to put it in a Try...Catch block but it didn't work.

What is the easiest way to find out what resources need to be released and how should I release a resource? How would I find out what process id holding up what resources?
 
Comment #11  (Posted by Mike McIntyre on 05/05/2004)

If a .NET Framework class can release the unmanaged resources it uses it will have a Dispose method.

Here you are using the static members of the File class, a class that does not have a Dispose method and is not recommended when you need to reuse an object several times.

The File class help topics says: All methods of the File class are static and can therefore be called without having an instance of a file. The FileInfo class contains only instance methods. The static methods of the File class perform security checks on all methods. If you are going to reuse an object several times, consider using the corresponding instance method of FileInfo instead, because the security check will not always be necessary.

The FileInfo class should work for you. Below is some sample code that uses FileInfo to create a file, delete it, and recreate it, all in the same method.

If this does not work for you it means you have a variable somewhere elese that is pointing at the file too.

---
Mike

Mike McIntyre [MVP Visual Basic]
Senior Developer/Partner
aZ Software Developers / www.getdotnetcode.com


********** Begin Example Code ****************

' Declare a variable of type FileInfo named _FileInfo.
' Use a FileInfo constructor to create a new FileInfo object.
' Assign the address (reference) of the new object
' to the _FileInfo variable.
Private _FileInfo As New FileInfo(Application.StartupPath &
"\DemoFile.txt")
' NOTE: For this demo the _FileInfo will work with a file name "DemoFile.txt" in
' this projects Bin directory. The Application.StartupPath method is used
' to help create a fully qualified file name. For more
' information about the StartupPath method
' click here --> http://msdn.microsoft.com/library/en-us/cpref/html/frlrfSystemWindowsFor
msApplicationClassTopic.asp?frame=true


Private Sub Example10Button_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Example10Button.Click
' Calls must be made to Refresh before attempting to get
' the attribute information, or the information will be outdated.
_FileInfo.Refresh()

' Use the FileInfo Exists method to make sure the file does not already exist.
If _FileInfo.Exists = False Then
'Create the "DemoFile.txt" file and use a StreamWriter to write to it.
Dim aStringWriter As StreamWriter = _FileInfo.CreateText()
aStringWriter.WriteLine("This file was created by a FileInfo
object.")
aStringWriter.WriteLine("The FileInfo class can be found the System.IO namespace.")
aStringWriter.Flush()
aStringWriter.Close()

_FileInfo.CreationTime = Now

Me.ReportRichTextBox.AppendText("The Demofile.txt file has been created in the Bin directory of this project. Here are its contents:" & vbCrLf & vbCrLf)

'Open and DemoFile.txt and use a stream reader to read from it.
Dim aStringReader As StreamReader = _FileInfo.OpenText()

Do While aStringReader.Peek() >= 0
Me.ReportRichTextBox.AppendText(aStringReader.ReadLine()
& vbCrLf)
Loop
aStringReader.Close()
End If


' Calls must be made to Refresh before attempting to get
' the attribute information, or the information will be outdated.
_FileInfo.Refresh()

Me.ReportRichTextBox.Clear()

If _FileInfo.Exists = True Then
' Call FileInfo's Delete method to delete the file associated with it.
_FileInfo.Delete()
Me.ReportRichTextBox.AppendText("DemoFile.txt has been deleted from the Bin directory of this project.")
Else
Me.ReportRichTextBox.AppendText("File does not exist.")
End If


' Calls must be made to Refresh before attempting to get
' the attribute information, or the information will be outdated.
_FileInfo.Refresh()

' Use the FileInfo Exists method to make sure the file does not already exist.
If _FileInfo.Exists = False Then
'Create the "DemoFile.txt" file and use a StreamWriter to write to it.
Dim aStringWriter As StreamWriter = _FileInfo.CreateText()
aStringWriter.WriteLine("This file was created by a FileInfo
object.")
aStringWriter.WriteLine("The FileInfo class can be found the System.IO namespace.")
aStringWriter.Flush()
aStringWriter.Close()

_FileInfo.CreationTime = Now

Me.ReportRichTextBox.AppendText("The Demofile.txt file has been created in the Bin directory of this project. Here are its contents:" & vbCrLf & vbCrLf)
End If

End Sub

************** End Example Code *************************
 
Comment #12  (Posted by Aaron on 05/05/2004)

[QUOTE]
Here are some facts which can be proven with any good diagnostic tool:

A. Close - Closes a connection, it does not dispose the connection.
B. Dispose - Closes and Disposes a connection.
C. Leaving any object referenced prevents it from being GCd.
D. Dereferencing a connection object without disposing it first leaves the connection object's UNMANAGED resrouces in limbo and untouchable by the GC - after the object itself is gone.
E. Any object which uses UNMANAGED resources (which is the case with a connection) must be disposed to release those resources.
[/QUOTE]

I had a question regarding point D. In the latter part of your article you state that GC can, in fact, eventually release the unmanaged resources due to the Finalize method that is implemented on each of the objects that contain managed resources - it just will take a lot longer. I'm I not understanding this correctly? Thanks.
 
Comment #13  (Posted by asitaaa on 05/05/2004)

Thanks a lot. I didn't even know I was using a static method. Is ist generally a good programming practice to avoid static classes/methods? How can one find out if a better class is available?
 
Comment #14  (Posted by Mike McIntyhre on 05/05/2004)

Aaron,

[QUOTE]
In the latter part of your article you state that GC can, in fact, eventually release the unmanaged resources due to the Finalize method that is implemented on each of the objects that contain managed resources - it just will take a lot longer.
[END QUOTE]

The article is correct as far as how the GC works with all but a very few objects that use unmanaged resources that include Finalizers to release their unmanaged resources.

The SqlConnection object, as discussed in the quote you provided (which is not a part of the article), is one of the few objects that can mis-behave depending on version used, and how and where it is implemented e.g. using the SqlConnection in Framework 1.0 for a high volume web site, if SqlConnection.Close is used and SqlConnection.Dispose is not called before the object is dereferenced, handle leaks occur.
 
Comment #15  (Posted by Mike McIntyre on 05/05/2004)

Asitaaa,

It is not a good programming practices to avoid static classes/methods. It is fine to use static methods for what they are meant for and there are many you can't live without e.g. the System.Math shared methods.

[QUOTE]How can one find out if a better class is available?

I learn by reading the .NET help topics for the classes e.g. in this situation if you would have searched .NET help for the File Class topic you would have read the bit about it not being good for reuse and it's recommendation to use FileInfo.

You may want to read the article again where I describe using .NET help to study Classes and Class member topics.

By the way, what you were trying to do is not as obvious as it could be in the documentation, so that is the main reason you had problems with it. I see this same question in many places on the web.

Good luck.

 
Comment #16  (Posted by Chui on 05/06/2004)

I have a program in VB.Net that communicates with the comm port to retrieve stock feed. I used the RS232 class found in MSDN example to create the object to open the port and to read data from the port. The data is coming in continuously once connected. The program was running fine when I run it from a Win 2K pro PC (with 512MB Ram) and when the port is connected to a dial up modem. However, the program crashes with the error "Out of memory exception" after running it for about 2 hours in a Win 2k Server with the port connected to a DB2 cable. The server has a 1GB RAM and from the Task Manager, the program does not consume alot of memory (about 10-20%) and the CPU usage is about 60-70%. Thinking that the code that process the data consumes the memory, I took out the code that process the data and the program only contains the code that retrieve that data and prints out the data into a rich text box using delegates. But the problem still occur. The retrieving subroutine is a do while loop that never stops unless there is no more data in the buffer. This subroutine is run from another thread. The object that connects to the port retrieves 1 byte of data at a time from the buffer and each byte will go through the loop for processing.

Suspecting that the class used is not written to cater for such a huge amount of data, I tried to use another component which is SAX.Net Lite Edition. However, the same problem persists. The only thing I can think of now is the mode the data comes in. The server is connected to a DB2 cable to get the stock feed, this is where my program crashes. The pc is connected to a dial up modem and the program works fine. Is there any difference by using a modem and the cable? Has it anything to do with the memory fragmentation? Here is a snippet of the code:

' Declare necessary class variables.
Private m_CommPort As New Rs232()
Private m_ModemPort As Integer = 0
Private WithEvents timerReadError As System.Timers.Timer

Private mobjThread As Thread

Public Delegate Sub DisplayInvoker(ByVal t As String)
Private debugString As New StringBuilder()

Private Sub getStockFeed()

' Always wrap up working with Comm Ports in exception handlers.
Try
stopRead = False
' stop the timer
timerReadError.Stop()

m_CommPort.ClearInputBuffer()
make sure that the previous open port session is closed first before opening a new port
m_CommPort.Close()
Attempt to open the port.
m_CommPort.Open(m_ModemPort, 19200, 8, Rs232.DataParity.Parity_None, Rs232.DataStopBit.StopBit_1, 10240)

'** create a new thread to start retrieving the feed
mobjThread = New Thread(AddressOf readCommPort)
mobjThread.Start()

Catch ex As Exception
' Warn the user.
rowColor = Color.Red
Me.Invoke(New DisplayInvoker(AddressOf Me.DisplayText), New Object() {vbCrLf & ex.Message & vbCrLf & ex.StackTrace})
timerReadError.Start()
End Try

End Sub

Private Sub readCommPort()

Dim rawdata As String
Dim isFid As Boolean = False
Dim startDV As Boolean = False
Dim raw As New StringBuilder()

Try
' As long as there is information, read one byte at a time and
' output it.
While stopRead = False
If m_CommPort.Read(1) = -1 Then
'** if the port stream closes itself, then close it and reopen
Call restartProcess()
Exit Sub
End If
rawdata = m_CommPort.InputStream(0)

If rawdata = "2" Or startFeed = True Then
'detected start of text
startFeed = True
raw.Append(rawdata & ".")

If rawdata = "2" Then
'Debug.WriteLine(vbCrLf & "###" & raw & "###")
Me.Invoke(New DisplayInvoker(AddressOf Me.DisplayText), New Object() {debugString.ToString & vbCrLf & "###" & raw.ToString & "###"})
raw.Remove(0, raw.Length)

'** swap color
rowColor = color1
color1 = color2
color2 = rowColor

'** the data processing will be here

End If
Else
'Debug.Write(m_CommPort.InputStreamString)
rowColor = Color.Red
Me.Invoke(New DisplayInvoker(AddressOf Me.DisplayText), New Object() {rawdata})
End If
End If
End While
Catch exc As Exception
'Debug.WriteLine(exc.Message & vbCrLf & exc.StackTrace)
rowColor = Color.Red
Me.Invoke(New DisplayInvoker(AddressOf Me.DisplayText), New Object() {vbCrLf & exc.Message & vbCrLf & exc.StackTrace})
'the timer will wait until it elapses before redialing.
timerReadError.Start()
End Try

End Sub
 
Comment #17  (Posted by Mike McIntyre on 05/06/2004)

Chui,

Please provide a link to the Microsoft example you are using.
 
Comment #18  (Posted by Chui on 05/06/2004)

Here is the link to the Microsoft sample:
http://www.microsoft.com/downloads/details.aspx?FamilyID=075318ca-e4f1-4846-912c-b4ed37a1578b&DisplayLang=en

I did some modifications to the code yesterday by removing the function to output the incoming data to the rich text box using delegates. Instead, I output the data to a console. In this way, the program does not give the OutOfMemoryException error anymore even though running it for the whole day! So, does this mean that the delegates or the rich text box that are consuming the memory? How can I fix this? Thanks for your help!
 
Comment #19  (Posted by sarin on 05/20/2004)

excellent..
 
Comment #20  (Posted by an unknown user on 06/10/2004)

a better thread on this topic:
http://www.devdex.com/asp/message.asp?p=&r=4209592&page=2

Basically, Dispose on a SqlConnection does little more than call close and clear a few other properties to prepare it for reuse.

Take a look with Reflector ( http://www.aisto.com/roeder/dotnet/ )
 
Comment #21  (Posted by Mike McIntyre on 06/11/2004)

Dispose calls close if the connection is open, sets some variables to nothing and calls dispose on the component. Calling Dispose on the component supresses finalization keeping the component from ever entering the finalization queue.

The code below shows what occurs in the components Dispose method after the SqlConnection's Dispose method calls MyBase.Dispose on the component. Notice the call to GC.SupressFinalize.

L_0008: call GC.SuppressFinalize

If Close is called instead of Dispose on the SqlConnection the connection is closed but MyBase.Dispose is not called on the component. GCFinalize will not be supressed and the component will needlessly get queued in the Finalization queue. In a high volume web site where a very high volume of of SqlConnections are instantiated, used, and abandoned the GC Finalization Queue bloats and causes some performance problems. (This was in Framwork 1.0x. I have not retested in 1.2x).

From the article, here is what happens to an object that could be disposed to suppress finalization is not disposed. Eventually it works its way through the finalization queue and get disposed but not without affecting performance.

**** from article *****
The GC does not remove objects which need to be finalized (objects that have not been disposed to supress finalization) 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.
**** end *****

The performance difference can only be seen in a web application making and releasing 1,000s of SqlConnections an hour. It is never seen in a Windows Forms application because Windows Forms never use the volume of SqlConnections a high volume web site can use.

The article is based on actual experience. Two years ago my company began a stress test of its first large ASP.NET application. After an hour of heavy testing the application slowed to a crawl. We consulted with Micrsoft who adivsed us to use Dispose instead. The problem was instantly gone. We tested using Close and Dispose while monitoring the GC. With Close the heap bloated faster than the GC could handle it, eventually slowing the application. With Dispose there was no problem. I have not retested with 1.2x .

C# programmers rarely have this problem because of the C# Using statement. Below is link explains how a C# Using wrapper on a SqlConnection object automatically Disposes a SqlConnection.

http://ryanfarley.com/blog/archive/2004/02/03/308.aspx
 
Comment #22  (Posted by Jimmy on 09/30/2004)

Thanks, that was gold.
 
Comment #23  (Posted by Rodrigo on 01/04/2005)
Rating
Hi to all:I have build an app to start SQL Server replication.Every 10 minutes, I start aprox. 50 replication using the SQLDistribution object.I start every replication in a child form of a main parent form.After replication is finished I close the child forms.Everytinh work great after 5 or 6 hours of running when I have strange problems refreshing the forms, and with the entire system. If I run other programs, they won't refresh and look strange.I have checked the GDI objects value from the Task Manager, and is start with a value of 100 and when it reaches 5000 is when I have the problem.Does my problem have anything to do with this topic? What should I check? How can I fix it?Any help would be great.Thanks to all
 
Comment #24  (Posted by an unknown user on 03/13/2005)
Rating
Hats off to you Mr. Mike.This is an fantastic article & have cleared all my doubts about GC. After reading this article I will be in a better position to manage my application resources.
 
Comment #25  (Posted by an unknown user on 03/25/2005)
Rating
good
 
Comment #26  (Posted by an unknown user on 04/07/2005)
Rating
This article contradicts nearly everything I've read, which is a great deal. However, using the information describe I was able to solve a kotty "resource in use" conflict caused by the System.Drawing.Image class.

Thank you.
 
Comment #27  (Posted by an unknown user on 04/17/2005)
Rating
first time asfter reading this article.i understand dispose and finalize
 
Comment #28  (Posted by M.M.Majid on 04/27/2005)
Rating
It is very helpful in understanding the object life time. I am using datareader to retrieve data from data acess layer and passing it to Application layer.I am closing the Datareader in Application layer but how can i closed the Connection as i am comming out of connection.
 
Comment #29  (Posted by Mike McIntyre on 04/27/2005)

One approach is to create a new class with both SqlDataReader and SqlConnection types as data members with assoiated properties. This will allow you to pass this class to your bussiness layer where you can use its SqlDataReader to read the data then its SqlConnection to close the connection.

However, passing data (e.g. a collection) rather than a data access component is generally considered a better approach - more in keeping with the separation you want to maintain between the layers.
 
Comment #30  (Posted by an unknown user on 05/02/2005)
Rating
Very helpful and informative. I was having trouble with the GarbageCollection process and this makes perfect sense!
 
Comment #31  (Posted by an unknown user on 05/02/2005)
Rating
Very helpful and informative. I was having trouble with the GarbageCollection process and this makes perfect sense!
 
Comment #32  (Posted by an unknown user on 05/27/2005)
Rating
A nice article to understand managed & unmanaged things
regards,
Naveen Dhawan
Software Programmer

 
Comment #33  (Posted by Naveen Dhawan on 05/27/2005)
Rating
A nice article to understand the things about managed and unmanaged.
 
Comment #34  (Posted by an unknown user on 06/08/2005)
Rating
Clear to read :)
 
Comment #35  (Posted by an unknown user on 07/18/2005)
Rating
We found the required matter in this article.
 
Comment #36  (Posted by Omar on 08/16/2005)
Rating
Help!!

I'm just trying to read an image from file and save it to deffirent path and generate a thumbnail image of it. and after that deleting the source image.

I got that the source is being used by another process. What that process could be? how can I free the img object (image object)?

----bigin code----
Dim img As Image
img = Image.FromFile("D:\ImagesDropFolder\29-18.JPG")
img.Save("C:\LIB_1.jpg")
img = img.GetThumbnailImage(32, 32, Nothing, Nothing)
img.Save("C:\Thumb_1.jpg")
File.Delete("D:\ImagesDropFolder\29-18.JPG")
-----end code-----

Additional information: The process cannot access the file "D:\ImagesDropFolder\29-18.JPG" because it is being used by another process.

Many thanks

Omar

 
Comment #37  (Posted by Mike McIntyre on 08/22/2005)

Omar, Regarding your two questions. Since they are off topic to the article please submitt them to one of the DevCity forums or email me directly.

Thanks ;-)
 
Comment #38  (Posted by an unknown user on 09/30/2005)
Rating
Very much clarifies .NETs Help references on this subject & provides a much more in-depth information. The examples given are quite simple, clarifying, rather than muddying the issue. Thankyou.
 
Comment #39  (Posted by an unknown user on 10/12/2005)
Rating
This article clarified the difference between nothing and dispose and saved me alot of headache.
 
Comment #40  (Posted by an unknown user on 10/15/2005)
Rating
Great article.
Thank you very much....
 
Comment #41  (Posted by J.J. on 10/17/2005)
Rating
With the following code:

[BEGIN]
Dim cmd As New SqlCommand

Try
With cmd
.Connection = New SqlConnection(...)
.CommandText = "sp..."
.CommandType = CommandType.StoredProcedure
.Parameters.Add("@year", SqlDbType.Int).Value = intYear
.Parameters.Add("@quarter", SqlDbType.Int).Value = intQuarter

cmd.Connection.Open()
cmd.ExecuteNonQuery()
End With

Finally
If Not cmd.connection Is Nothing Then cmd.connection.Dispose()
End Try
[END]

Do I need to Dispose the SqlCommand object cmd?
If I created a seperate variable cn to hold the connection object, do I need to dispose the SqlCommand object cmd?
 
Comment #42  (Posted by Zoila on 10/19/2005)
Rating
Very informative. Thanks Mike
 
Comment #43  (Posted by Clayton Armstrong on 11/02/2005)
Rating
Your "good code" is actually bad. Dispose should ALWAYS be called in a finally block, or an equivalent, such as provided by the "using" statement in C#.

Cleanup obviously must be included in a finally block or similar if you want it to always run.
 
Comment #44  (Posted by Mike McIntyre on 11/02/2005)

Of course. The point the good and bad code to clearly explain what happens to resources when making the calls the two different ways shown, not how to implement exception handling around the calls.
 
Comment #45  (Posted by Matt on 11/15/2005)
Rating
Very good article, but one thing that has left me a little confused is when to use the Finalize() method to clean up objects when creating a class.

If i create a simple class that uses a connection object which is public. this connection object can be opened, closed and disposed by accessing myobject.connection.dispose etc.

However if the dispose method is not called when myobject is no longer required, the class contains a finalise method :-

Protected Overrides Sub Finalize()
_Connection.Dispose()

MyBase.Finalize()
End Sub

This simply insures that the connections dispose method is called when the object is collected by the GC. Other articals however claim that .close or .dispose should never be included in a finalise method:

http://www.15seconds.com/issue/040830.htm

'Last but not the least, never Close or Dispose your connection or any other managed object in the class destructor or your Finalize method. This not only has no value in closing your connections but also interferes with the garbage collector and may cause errors.'

is it wrong to use the finalize() method in this way?

thanks

 
Comment #46  (Posted by an unknown user on 12/05/2005)
Rating
This is wrong...
' 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()

If you look at the IL for Close and Dispose, you will see that the only intersting thing Dispose does is call Close. Close, like the name implies, is the one that actually closes the unmanaged database connection. (Or returns it to the connection pool.)

 
Comment #47  (Posted by an unknown user on 01/30/2006)
Rating
Thank you very much ! Your article is very good !
Gabriela

 
Comment #48  (Posted by an unknown user on 02/17/2006)
Rating
Great article!!
 
Comment #49  (Posted by an unknown user on 03/13/2006)
Rating
This is quiet informative about effective memory management and i learned and enjoyed the tips in the articles. Thanks Mike.
 
Comment #50  (Posted by an unknown user on 05/03/2006)
Rating
its has tuched all the topics related to GC. Even what is managed & unmanaged resource.
 
Comment #51  (Posted by an unknown user on 05/08/2006)
Rating
Very helpful document. Helped me to understand why my app is leaking memory.
 
Comment #52  (Posted by an unknown user on 05/10/2006)
Rating
Brilliany article.. Explains weel with example. That really helps me.. Thanks..
 
Comment #53  (Posted by an unknown user on 08/01/2006)
Rating
Been tearing my hair out for hours till I ran across this. Thanks for giving me back my sanity!
 
Comment #54  (Posted by an unknown user on 10/10/2006)
Rating
Simple and excellent Presentation.
 
Comment #55  (Posted by an unknown user on 11/02/2006)
Rating
Good article. I wish the book I read was as clear when it discussed this.
 
Comment #56  (Posted by an unknown user on 11/02/2006)
Rating
Good article. I wish the book I read was as clear when it discussed this.
 
Comment #57  (Posted by an unknown user on 11/10/2006)
Rating
Actually I was searching for some 'real-time' examples of managed and unmanaged resources used by .NET framework. I identified them at the bottom of this article in 'Black-and-White'. So I liked this article.
 
Comment #58  (Posted by an unknown user on 11/28/2006)
Rating
Thanks! Great article! I am working on solving a memory leak and this has helped me to understand the .net GC. I wonder if this applies to 1.1 and 2.0 frameworks the same way...
 
Comment #59  (Posted by an unknown user on 11/28/2006)
Rating
This article applies to 1.1 and 2.0. Mike McIntyre
 
Comment #60  (Posted by an unknown user on 01/20/2007)
Rating
There was a case where I used an SQL Connection and By default sql pooling was true. In my code I was also using 3rd Party dll. I had a Large memory leak as the objects were not destroyed when they went out of scope. I ddisposed every object I created but the 3rd party dll did not dispose it's object. The problem was finally traced to sql database call. Making pooling = false in the connection string solved the problem. Can anyone tell me y??? If some one knows the answer please mail me at eabhimanyu@yahoo.com. We used vb.net 1.1 for coding and sql server 2000 as database.
 
Comment #61  (Posted by an unknown user on 01/24/2007)
Rating
Ya this is the Excellent article
 
Comment #62  (Posted by an unknown user on 02/21/2007)
Rating
This is the best artice I read on GC!!!
 
Comment #63  (Posted by an unknown user on 02/26/2007)
Rating
Very informative. Thankyou!
 
Comment #64  (Posted by an unknown user on 04/20/2007)
Rating
No one else would tell me what an unmanaged resource vs a managed resource is in terms I understood.
 
Comment #65  (Posted by an unknown user on 08/08/2007)
Rating
Excellent
 
Comment #66  (Posted by an unknown user on 10/02/2007)
Rating
Mike, One of the best articles I came across with respect to Managed vs Unmanaged resources. The article is upto the point and you did an excellent job putting this together.
 
Comment #67  (Posted by an unknown user on 10/10/2007)
Rating
I appreciate the depth the author took this topic. It really opened my eyes to a much better way of improving application performance.
 
Comment #68  (Posted by an unknown user on 04/19/2008)
Rating
I have a large VB.NET 2005 app and this article really helped. I think I have a memory leak somewhere in my application but have not tracked it down yet.

On all my extended controls I have a dispose and finalize method. But, my question is on combo box. Do you need to dispose of the datasource seperatly? I have several combos that are used but I thought the dispose would be taken care of in the components.dispose. Is this something I need to dispose of separately?
 
Comment #69  (Posted by an unknown user on 05/27/2008)
Rating
This article was a big help, I was sporadically using the dispose method with focucing on the methodolligy behind it. I also was having a problem with the System.Drawing.Image Class and this cleared thing up.

 
Comment #70  (Posted by an unknown user on 08/07/2008)
Rating
This was a gigantic help -- A simple temporary RichTextBox object I was creating in a subroutine was sucking up 48-96K per second! Just knowing that objects need to be disposed solved the issue. ALSO - The tip of using the Intellisence was huge. Thank you!
 
Comment #71  (Posted by an unknown user on 08/20/2008)
Rating
Just what I was looking for. Refreshingly clear (I just hope it's correct).
 
Comment #72  (Posted by an unknown user on 10/07/2008)
Rating
very infomative article. it helps me too much
 
Comment #73  (Posted by an unknown user on 11/22/2008)
Rating
This is good artical.
 
Comment #74  (Posted by an unknown user on 11/22/2008)
Rating
This is good artical.
 
Comment #75  (Posted by an unknown user on 01/22/2009)
Rating
I wish I had low-level knowledge like this guy... it's really a lost art. All the cushy IDE and system integration has caused us to have less responsibility, maybe a little less hassle, but also less knowledge of system architecture. Rated a 5.
 
Comment #76  (Posted by Pvdv on 02/11/2009)
Rating
If a object implements the System.IDisposable then
with vb2008 you can use the USING

Using 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.

End Using

And it Disposes of the varable before exiting the code.
 
Comment #77  (Posted by an unknown user on 05/04/2009)
Rating
Excellent article ! I ll have somework today... Checking all my source code
 
Comment #78  (Posted by an unknown user on 05/05/2009)
Rating
It told me why the memory visible in TaskManager for my VB.NET program grew and grew, and what to do about it.

Probably should mention that fileio has a dispose method!
 
Sponsored Links