Memory leak with Datagrid and array

G

Guest

I have a simple windows application that has a function to read a csv file
and enter the values into an array A as double(,). Also, an instance of form
2 (which has a DataGrid) is created and the values of A are used to populate
the grid via a DataView. The instance of form2 is called Matrix_A . The basic
layout is as follows:

#Region "Globals
Dim A As Double(,)
Dim Matrix_A As form2
#End Region

Private Sub OpenA()
OpenCsv() 'simple read-in procedure
populateA()
End Sub

Private Sub populateA()
If Not Matrix_A Is Nothing Then
Matrix_A.Close()
End If
Matrix_A = New form2
array_to_grid(A, Matrix_A.DataGrid1)
Matrix_A.MdiParent = Me
Matrix_A.Show()
End Sub

Sub array_to_grid(ByVal array(,) As Double, ByRef dg As DataGrid)
Try
Dim Rows As Integer = array.GetLength(0) - 1
Dim Cols As Integer = array.GetLength(1) - 1
Dim dta As New DataTable("matrix")
Dim dca(Cols) As DataColumn
Dim dra(Rows) As DataRow
Dim dv As New DataView(dta)
dv.AllowNew = False
'loop in columns
Dim i As Integer = 0
Dim j As Integer = 0
For j = 0 To Cols - 1
dca(j) = New DataColumn("")
dca(j).DataType = System.Type.GetType("System.Single")
dta.Columns.Add(dca(j))
Next
'create rows
For i = 0 To Rows - 1
dra(i) = dta.NewRow
For j = 0 To Cols - 1
dra(i)(j) = array(i + 1, j + 1)
Next j
Next i
'add rows to table
For i = 0 To Rows - 1
dta.Rows.Add(dra(i))
Next
'bind the dataview to the grid
dg.DataSource = Nothing
dg.DataSource = dv
Catch ex As Exception
MsgBox(ex.Message)
End Try
End Sub

When I first start my program, I use about 19M memory (task mngr). When I
load a 2500X2500 matrix I use about 42M.

I then execute the sub:

Private Sub clear_Matrices()
Matrix_A.Close()
Erase A
GC.Collect() 'added later in attempt to solve problem
GC.WaitForPendingFinalizers() 'added later
End Sub

I would expect the memory use to revert to 19M but it does not. It stays up
around 40M. I am not enough of an expert to properly interpret results from
CLRProfiler but it appears that a considerable amount of memory is still tied
up in dataview, datatable, and datacolumn stuff even after the instance of
form2 containing the datagrid has been closed.

How can I make my application not leak memory?
 
G

Guest

Hi,

After you close matrix_a you should displose of it.
Matrix_A.Dispose() The data is still in the datagrid so do not forget to set
the datagrid datasource = nothing.

Ken
 
G

Guest

Now my close method is:

Private Sub clear_Matrices()
Matrix_A.Close()

Matrix_A.DataGrid1.DataSource = Nothing
Matrix_A.Dispose()

Erase A
GC.Collect() 'added later in attempt to solve problem
GC.WaitForPendingFinalizers() 'added later
End Sub

However, the memory problem persists. At least as I view it from the task
mngr as I run the program in debug mode.
 
G

Guest

Mark,

Google for the articles that explain why Task Manager is an inappropriate
tool for measuring .Net memory usage.

Kerry Moorman
 
G

Guest

Thanks,

It is probably a new thread question but I understand my P4 HT processor to
have a 32 bit address bus and a 32 bit bit data bus and that the comming
generations will have both at 64 bits. Do I have this right???
 
T

TP

Matrix_A still has a reference to your instance of form2,
so the GC will not collect it. After your dispose, you
could add

Matrix_A = Nothing

to remove the reference.

Your original instinct was correct--if you profile your app
with CLRProfiler, you should not see instances of form2
and the objects it contains when form2 has been closed.

In addition to the doc that comes with clrprofiler, there are
a few good basic tutorials that walk you through finding
and correcting .net memory leaks here:

http://www.scitech.se/memprofiler/tutorials/

You don't have to own their profiler software to follow
the tutorials and increase your understanding.

When using task manager, you should turn on the column
that shows Private Bytes. It is under the select columns
menu and is labeled "VM Size".

For detailed information on windows memory management
and interpreting the performance counters I STRONGLY
recommend Chapter 7 of Microsoft Windows Internals:

http://www.amazon.com/gp/product/07...104-4362545-6814301?s=books&v=glance&n=283155

The above book will answer your questions regarding 32-bit,
64-bit, working set, private bytes, etc.

Thanks.

-TP
 
G

Guest

TP:

I ordered the book.
I see Tyan makes motherboards for MP systems with both 2 and 4 processor
(AMD Opteron 200 and 800 series) configurations. Do you know if it is
possible to specifically target a given processor for execution of a
specified thread from VB.net?
 
T

TP

Take a look at SetThreadAffinityMask and SetThreadIdealProcessor:

http://msdn.microsoft.com/library/d...ry/en-us/dllproc/base/multiple_processors.asp

For the .NET way to set affinity, take a look here:

http://msdn.microsoft.com/en-us/library/system.diagnostics.processthread.processoraffinity.aspx
http://msdn.microsoft.com/en-us/library//system.diagnostics.processthread.idealprocessor.aspx

Setting affinity is not generally recommended, so you should test to see
if it makes sense for you.

The Microsoft Windows Internals book has tons of information about
how windows handles scheduling, priority, etc., so you should definitely
read that to learn more.

Thanks.

-TP
 
G

Guest

So, I close, dispose and set the datagrid=nothing. I also hear that I should
set Matrix_A = Nothing . Seems like quite a bit to flush out all the
resources tied-up in this form.

The .net help says "When a form is closed, all resources created within the
object are closed and the form is disposed. A recursive analysis of this
definition indicates that the Datagrid is closed ergo it is disposed and all
of the resources used by it are closed."

Are datagrids handled differently than typical resources here?

At this point I have the following sequence of statements

Matrix_A.Close()
Matrix_A.DataGrid1.DataSource = Nothing
Matrix_A.Dispose()
Matrix_A = Nothing
GC.Collect()
GC.WaitForPendingFinalizers()

Is the above necessary and sufficient for annihilation of the form2
instance Matrix_A and for freeing all of the resources used by it?

Also, This instance of form2 is a child of form1 which the user could close
by clicking the close control in the top right corner. I'll need to override
form2.closing and include the extra clean-up code?
 
T

TP

You don't need all that you have listed.

Let's step through things:

Matrix_A.Close() ' Closes the modeless form and implicitly calls Dispose
Matrix_A = Nothing ' Removes the reference to the form2 instance

Now, at this point there are no references to the form2 instance, so
it and its contents are eligible for garbage collection. The only reason
you need the Matrix_A = Nothing is because Matrix_A is a global
variable. If not for that you would be down to simply Matrix_A.Close().

GC.Collect() ' Force a garbage collection
GC.WaitForPendingFinalizers()

For learning purposes it is good to use the clrprofiler and verify for
yourself that form2 and all of its contents are no longer in memory.
Look at the heap graph with detail set to 0 (everything) and search
for form2 or any of its contents. Try this exercise with and without
setting Matrix_A = Nothing after closing the form and see what
results you get.

http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dndotnet/html/dotnetgcbasics.asp

Thanks.

-TP
 
G

Guest

um. . . back up here. . .
Why load the array and then unload to the grid?
Doing things the old VBSUX way????
Well that was wrong in VBSUX, too!

use an OleDbDataAdapter to open a csv file
use it to fill a datatable
bind to datagrid
the data is in the datatable, displayed in the datagrid.

4 lines of code (datafile is c:\TextFiles\test.csv):

Dim dt As New DataTable
Protected Overrides Sub OnLoad(ByVal e As System.EventArgs)
Dim da As New OleDbDataAdapter("select * from test#csv", _
"Provider=Microsoft.Jet.OLEDB.4.0;" & _
"Data Source=C:\TextFiles;Extended
Properties=""text;HDR=No;FMT=Delimited""")
da.Fill(dt)
DataGrid1.DataSource = dt
da.Dispose()
End Sub
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top