The EntitySpaces Community

Share and learn about the EntitySpaces Architecture.
Welcome to The EntitySpaces Community Sign in | Join | Help
in
Home Forums Photos

Slightly Off-Topic - DataGridView memory

Last post 02-11-2008, 1:14 PM by quimbo. 11 replies.
Sort Posts: Previous Next
  •  02-05-2008, 8:40 AM 7909

    Slightly Off-Topic - DataGridView memory

    i have researched this for the past day and am posting here in case someone can help

     i have an application that has user controls that contain a DataGridView.  Each DGV is bound to a binding source and the binding source is an ES collection that gets reloaded at each refresh.  I noticed that each time i refresh the grid, the amount of memory in use goes up.  I ran a memory profiler and i can see things like DataRows, DataGridTextBoxCell, etc counts continue to climb while the number of rows in the collection/bindingsource/DGV is fairly low.  i have tried all different kinds of disposes, etc and i cannot get this memory to ever be released. 

    the only thing i have not tried is to destroy and recreate the grid each time

    here is the pertinent code:

     

    RefreshData gets called either when a timer runs down or a user clicks a button/ 

     

     

    Code:
        Private problemColl As BusinessObjects.CallRequestCollection
        Private probBindSource As BindingSource
    
    
        Private Sub RefreshData()
          Dim procName As String = "RefreshData"
            Dim currentRow As String = String.Empty
            Dim problems As BusinessObjects.CallRequestQuery
            Dim client As BusinessObjects.ClientQuery
            Dim intNotes As BusinessObjects.InternalNotesQuery
            Dim patResults As BusinessObjects.PatientresultsQuery
            Dim singleOC As BusinessObjects.SingleocAcnQuery
    
            Timer1.Stop()
            Me.Cursor = Cursors.WaitCursor
            Me.Focus()
    
            uxFromDate.MaxDate = Today
            uxThruDate.MaxDate = Today
    
            currentAccession = String.Empty
    
            Dim sortCol As New DataGridViewColumn
            sortCol = probGrid.SortedColumn
            Dim sortOrder As New System.Windows.Forms.SortOrder
            If Not sortCol Is Nothing Then
                sortOrder = probGrid.SortOrder
            Else
                sortCol = probGrid.Columns("ProblemStatus")
                sortOrder = Windows.Forms.SortOrder.Ascending
            End If
    
            Try
    
                DirectCast(Me.ParentForm, MainForm).DisplayStatus("Refreshing Problem Accessions... " & Now)
    
                If Not IsNothing(problemColl) Then
                    If problemColl.Count > 0 Then
                        currentRow = probGrid.CurrentRow.Cells(Enums.ProbGrid.Accession).Value.ToString()
                  
                    End If
    
                    problemColl.Dispose()
                    problemColl = Nothing
                    probGrid.DataSource = 
                    probGrid.Rows.Clear()
                    probGrid.Refresh()
                End If
    
                problemColl = New BusinessObjects.CallRequestCollection

    problems = New BusinessObjects.CallRequestQuery("p")
    client = New BusinessObjects.ClientQuery("c")
    intNotes = New BusinessObjects.InternalNotesQuery("n")
    patResults = New BusinessObjects.PatientresultsQuery("r")
    singleOC = New BusinessObjects.SingleocAcnQuery("s")

    problems.Select(problems.CallRequestID, problems.RequestNumber, _
    problems.ProblemCreated, problems.ProblemStatusID, problems.OrderSiteID, _
    problems.Accession, client.Name, client.Officephone, problems.PatientName, _
    problems.IsStatSlab, singleOC.Collectdate, patResults.Result, intNotes.Notes)

    problems.InnerJoin(singleOC).On(problems.Accession = singleOC.Accession)
    problems.LeftJoin(patResults).On(problems.Accession = patResults.Accession)
    problems.InnerJoin(client).On(problems.OrderClientID = client.Clientid)
    problems.LeftJoin(intNotes).On(problems.Accession = intNotes.Accession)

    problems.Where(problems.HasProblem = 1)

    If uxProblemStatusSpecific.SelectedIndex <> -1 Then problems.Where(problems.ProblemStatusID = _ CType(uxProblemStatusSpecific.SelectedValue.ToString(), Integer))
    Else
    If
    uxProblemStatus.SelectedIndex <> -1 Then problems.Where(problems.ProblemStatusID <= _ CType(uxProblemStatus.SelectedValue.ToString(), Integer))
    End If
    End If
    problems.Where(singleOC.Ordercode = "PROB")
    problems.Where(patResults.Ordercode = "PROB")

    If uxProblemStatusSpecific.SelectedIndex > -1 Then
    If
    uxProblemStatusSpecific.SelectedValue.ToString() = "3" Then problems.Where(problems.ProblemCreated.Between(CType(uxFromDate.Value.Date & " 00:00:00.000", DateTime), _
    CType(uxThruDate.Value.Date & " 23:59:59.997", DateTime)))
    End If
    End If

    If
    uxProblemStatus.SelectedIndex > -1 Then
    If
    uxProblemStatus.SelectedValue.ToString() = "3" Then problems.Where(problems.ProblemCreated.Between(CType(uxFromDate.Value.Date & " 00:00:00.000", DateTime), _
    CType(uxThruDate.Value.Date & " 23:59:59.997", DateTime)))
    End If
    End If
    problems.OrderBy(problems.ProblemCreated.Ascending) problemColl.Load(problems) mformLoading = True
    If
    probBindSource IsNot Nothing Then probBindSource = Nothing 'probBindSource.Dispose() GC.Collect() GC.WaitForPendingFinalizers() End If probBindSource = New BindingSource
    probBindSource.DataSource = problemColl

    mformLoading = False probGrid.DataSource = Nothing Debug.WriteLine(GC.GetTotalMemory(False))
    GC.Collect()
    Debug.WriteLine(GC.GetTotalMemory(False))

    probGrid.DataSource = probBindSource
    probGrid.Refresh()

    If sortOrder = Windows.Forms.SortOrder.Ascending Then probGrid.Sort(sortCol, System.ComponentModel.ListSortDirection.Ascending) Else probGrid.Sort(sortCol, System.ComponentModel.ListSortDirection.Descending) End If

    If
    problemColl.Count > 0 Then
    If
    currentRow.Length > 0 Then
    Dim
    gridRowIndex As Integer = probBindSource.Find("Accession", currentRow)
    If gridRowIndex <> -1 Then probGrid.CurrentCell = probGrid.Rows(gridRowIndex).Cells(Enums.ProbGrid.Accession) probGrid.Rows(gridRowIndex).Selected = True currentAccession = CType(probGrid.Rows(gridRowIndex).Cells(Enums.ProbGrid.Accession).Value, String)
    Else probGrid.CurrentCell = probGrid.Rows(0).Cells(Enums.ProbGrid.Accession) probGrid.Rows(0).Selected = True currentAccession = CType(probGrid.Rows(0).Cells(Enums.ProbGrid.Accession).Value, String)
    End If
    Else
    probGrid.CurrentCell = probGrid.Rows(0).Cells(Enums.ProbGrid.Accession) probGrid.Rows(0).Selected = True currentAccession = CType(probGrid.Rows(0).Cells(Enums.ProbGrid.Accession).Value, String)
    End If LoadTests() LoadComments() End If GetLastUpdate(slabTime, misysTime, nowTime) KryptonHeaderGroup1.ValuesSecondary.Heading = problemColl.Count & " Problems Displayed - Last SLAB Update: " & slabTime

    KryptonHeaderGroup1.ValuesSecondary.Description = "Next Refresh: " & DateAdd(DateInterval.Second, timeLeft, Now)

    Catch ex As Exception

    AppHandler.AddLogEntry("E", MODNAME & "::" & procName, 0, ex.Message.ToString(), ex.Source.ToString())

    AppHandler.MailError(MODNAME, procName, ex)

    AppHandler.ShowError(errMsgUnhandled, "Unhandled Exception Detected")

    Finally

    Me
    .Cursor = Cursors.Default

    DirectCast
    (Me.ParentForm, MainForm).DisplayStatus(String.Empty)

    Timer1.Interval = 1000
    timeLeft = GetTimeLeft(settingProbCheckMFDay, settingProbCheckMFNight, settingProbCheckSSDay, settingProbCheckSSNight)
    Timer1.Start()
    Me.ActiveControl = probGrid

    For Each f As Form In imageForms
    If f.WindowState <> FormWindowState.Minimized Then f.Activate() End If
    Next

    End Try
    problems = Nothing Debug.WriteLine(GC.GetTotalMemory(False))
    GC.Collect()
    Debug.WriteLine(GC.GetTotalMemory(False))
    End Sub
     
  •  02-05-2008, 8:57 AM 7910 in reply to 7909

    Re: Slightly Off-Topic - DataGridView memory

    If your app is a Windows App try this and you will simply be amazed. Let it build up it's memory by playing with it for a while, then Minimize it and Restore it and BAM, the memory drops to nothing. This is a Windows thing and not an ES thing, I can give you some code that can accomplish the same thing that minimizing does. I'm just not sure you have a Windows App though. Try my little experiment and see what you find out.

    EntitySpaces | Twitter | BLOG | Please honor our Software License
  •  02-05-2008, 9:10 AM 7911 in reply to 7910

    Re: Slightly Off-Topic - DataGridView memory

    This is what the "Free Memory" menu item in MyGeneration does. On some machines for reasons unknown memory in .NET does not behave well.

     

    Code:
    public static void FlushMemory()
    {
        try
        {
            GC.Collect();
            GC.WaitForPendingFinalizers();
            if (Environment.OSVersion.Platform == PlatformID.Win32NT)
            {
                SetProcessWorkingSetSize(System.Diagnostics.Process.GetCurrentProcess().Handle, -1, -1);
            }
        }
        catch { }
    }
     

    - Mike 

     


    EntitySpaces | Twitter | BLOG | Please honor our Software License
  •  02-05-2008, 9:13 AM 7912 in reply to 7910

    Re: Slightly Off-Topic - DataGridView memory

    Thanx...

    It is a windows app. i have tried this just now and it does not appear to work. (i tried both the compiled executable and from the IDE in debug mode

    the grids are on a user control that is loaded on a navigator control .

    http://www.componentfactory.com/products.php#navigator 

    When i close the 'page' that my grid is on, the memory also is not released so perhaps it is the control that is preventing this 

     i would love to see the code so that i can explore this further.

    i have tried just about everything with the collection, binding source and datagridview. 


     

     

     

  •  02-05-2008, 9:49 AM 7913 in reply to 7911

    Re: Slightly Off-Topic - DataGridView memory

    i put the code in, and it does not appear to work for me.  i will let my process run for a few hours, (the refresh is every minute) and see what happens. 
  •  02-05-2008, 12:44 PM 7915 in reply to 7913

    Re: Slightly Off-Topic - DataGridView memory

    It appears then that the memory cannot be reclaimed, something is still "pointing" to it.

    EntitySpaces | Twitter | BLOG | Please honor our Software License
  •  02-05-2008, 1:11 PM 7916 in reply to 7915

    Re: Slightly Off-Topic - DataGridView memory

    yes, and i cant imagine what it is.  i will contact the author of the navigator control i use

     

    thanx for your help

  •  02-06-2008, 8:55 AM 7922 in reply to 7915

    Re: Slightly Off-Topic - DataGridView memory

    I have looked at this some more, i have FlushMemory calls in appropriate places.  Using Process Explorer from Sysinternals, I see now that Working Set under Physical Memory is in fact being decreased significantly.  The Private Bytes under Virtual Memory is what continues to grow.  When i run a version without the FlushMemory calls side by side, its Virtual Memory - Private Bytes and Physical Memory - Working Set both grow. 
  •  02-06-2008, 9:27 AM 7923 in reply to 7922

    Re: Slightly Off-Topic - DataGridView memory

    Are you sure this is even a problem? The way Windows handles memory is kind of elusive these days. I would do some research on that, what you're seeing might be perfectly normal?

    EntitySpaces | Twitter | BLOG | Please honor our Software License
  •  02-06-2008, 9:37 AM 7924 in reply to 7923

    Re: Slightly Off-Topic - DataGridView memory

    I think that i will be fine with this.  just happy to reduce the physical memory.  will run both versions over night, refreshing every minute, to see the overall difference.

    Thanxs for the FlushMemory routine. 

     

  •  02-11-2008, 11:09 AM 8004 in reply to 7924

    Re: Slightly Off-Topic - DataGridView memory

    There are still some lingering memory issues, though not as large. 

    Since my collections are fairly small, i am toying with serializing the collection to a Byte Array, reloading the collection, serializing that to a Byte Array and then compare the 2 byte arrays to determine if i need to refresh/rebind the datagridview.    Initial testing on my first form shows that less memory is being consumed. 

     

    I used the Serialization Helpers found here

    http://community.entityspaces.net/forums/thread/7332.aspx 

    Here is my compare Function 

     

     

    Code:
      Public Function CompareByteArrays(ByVal abyt1() As Byte, ByVal abyt2() As Byte) As Boolean
    
            If abyt1.Length <> abyt2.Length Then
                Return False
            Else
                Dim i As Integer
                For i = 0 To abyt1.Length - 1
                    If abyt1(i) <> abyt2(i) Then
                        Return False
                    End If
                Next i
            End If
            Return True
        End Function
     
  •  02-11-2008, 1:14 PM 8006 in reply to 8004

    Re: Slightly Off-Topic - DataGridView memory

    here is a slightly faster Byte Array compare routine

     Code:

    Imports System.Security.Cryptography
    
     Public Function CompareByteArrays2(ByVal abyt1() As Byte, ByVal abyt2() As Byte) As Boolean
    
            If abyt1.Length <> abyt2.Length Then
                Return False
            Else
    
                Dim Hash1() As Byte = New MD5CryptoServiceProvider().ComputeHash(abyt1)
                Dim Hash2() As Byte = New MD5CryptoServiceProvider().ComputeHash(abyt2)
                For i As Int32 = 0 To 15
                    If Hash1(i) <> Hash2(i) Then
                        Return False
                    End If
                Next
            End If
            Return True
    
        End Function
    
    
    
     
View as RSS news feed in XML