0

I have an application that refreshes data every 30 seconds. On the main page, a dynamic control is added for each item of data. When the timer gets triggered, the controls are disposed, set to nothing, and the tab page is cleared.

The problem is that they do no dispose, private bites keep building with every refresh. Around 70mb private bytes, the application crashes with Message=Error creating window handle. NativeErrorCode=1158. It can be any control on the form that gets the error.

Tried using System.GC.Collect(), overriding Dispose on the control, and many other techniques that I have found related to this issue.

I do not think Dispose or Garbage collect actually work. This is the sub that clears the controls.

Revised code (simplified):

Sub ClearHotLists()
    For i As Int16 = ControlCollection.Count - 1 To 0 Step -1
        ControlCollection(i).Dispose()
    Next
End Sub

Private Sub TimerHotList_Tick(sender As Object, e As EventArgs) Handles TimerHotList.Tick
    PopulateHotList(False)
End Sub

Sub PopulateHotList(Connect)

    ClearHotLists()

    ControlCollection.Clear()

    Dim hpos As Int16 = 10
    Dim vpos As Int16 = 10

    If Connect Then sqlConn.Open()

    sqlConn3.Open()

    Select Case Me.tcMain.SelectedIndex

        Case 0
            AddHotListItems("Ground", hpos, vpos, Me.tabShipping)
            vpos += 230 : hpos = 10
            AddHotListItems("Hand Carry", hpos, vpos, Me.tabShipping)
            vpos += 230 : hpos = 10
            AddHotListItems("Red", hpos, vpos, Me.tabShipping)
            vpos += 230 : hpos = 10
            AddHotListItems("Outside Vendor", hpos, vpos, Me.tabShipping)
        Case 1
            hpos = 10 : vpos = 10
            For i As Int16 = 0 To InspCnt - 1
                AddHotListItems(InspArr(i), hpos, vpos, Me.tabInspection)
                vpos += 230 : hpos = 10
            Next
        Case 2
            hpos = 10 : vpos = 10
            For i As Int16 = 0 To DebCnt - 1
                AddHotListItems(DebArr(i), hpos, vpos, Me.tabDeburring)
                vpos += 230 : hpos = 10
            Next

    End Select

    sqlConn3.Close()

    If Connect Then sqlConn.Close()

End Sub

Sub AddHotListItems(ByVal ItemType As String, ByRef hpos As Int16, ByRef vpos As Int16, ByVal Tab As TabPage)

        Dim DynHotListItem As HotListItem
        Dim ControlObject As Control
        sql = "SELECT * FROM tWhiteBoardHotList WHERE Type='" & ItemType & "' ORDER BY PartNumber"
        sqlComm = New OdbcCommand(sql, sqlConn)
        r = sqlComm.ExecuteReader
        While r.Read
            ControlObject = New HotListItem
            ControlObject.Location = New System.Drawing.Point(vpos, hpos + DynLabel.Height)
            Tab.Controls.Add(ControlObject)
            DynHotListItem = ControlObject
            DynHotListItem.lblPartNumber.Text = r!PartNumber

            'BUNCH OF CODE HERE TO FILL THE CONTROLS ON HotListItem

            ControlCollection.Add(DynHotListItem)

        End While
        r.Close()

End Sub

Original Code : Sub ClearHotLists()

    Dim DynHotListItem As HotListItem
    Dim DynLabel As Label

    For Each DynTabPage As TabPage In Me.tcMain.Controls
        If DynTabPage.Name = "tabShipping" Or DynTabPage.Name = "tabInspection" Or DynTabPage.Name = "tabDeburring" Then
            For Each ctr As Control In DynTabPage.Controls
                If TypeOf ctr Is HotListItem Then
                    DynHotListItem = ctr
                    DynHotListItem.Dispose()
                    DynHotListItem = Nothing
                    DynTabPage.Controls.Remove(DynHotListItem)
                    ctr.Dispose()
                Else
                    DynLabel = ctr
                    DynLabel.Dispose()
                    DynLabel = Nothing
                    DynTabPage.Controls.Remove(DynLabel)
                    ctr.Dispose()
                End If
            Next
            DynTabPage.Controls.Clear()
        End If
    Next

    System.GC.Collect(GCCollectionMode.Forced)
    System.GC.Collect(0, GCCollectionMode.Forced)
    System.GC.Collect(1, GCCollectionMode.Forced)
    System.GC.Collect(2, GCCollectionMode.Forced)

End Sub

Expected result is for the controls to be disposed, and avoid crashes because of memory leaks.

Mitch
  • 11
  • 1
  • 2
    You are hiding the bugs in your code with the Controls.Remove() and Controls.Clear() calls. You must delete them to get ahead. Disposing a control from a collection you iterate is only valid when you iterate it backwards, use a For-loop. – Hans Passant Mar 26 '19 at 17:21
  • Thanks Hans, but how to you delete the control from the form? I thought remove was supposed to do that. I am not sure what you mean by looping it backwards? – Mitch Mar 26 '19 at 17:30
  • Remove() does not delete anything, it only removes the control from its parent. With the assumption that you'll put it back again some time later, or give it a different parent, but you don't do that. So it leaks forever and eventually crashes your program when you did this ten thousand times. You must use Dispose(). Since you are not selective about what you get rid of you can simply use While DynTabPage.Controls.Count > 0: DynTabPage.Controls(0).Dispose: End While – Hans Passant Mar 26 '19 at 17:41
  • https://stackoverflow.com/a/952152/17034 – Hans Passant Mar 26 '19 at 17:43
  • Still same issue. Thanks for you suggestions. I have tried everything. – Mitch Mar 26 '19 at 18:08
  • Post the reviewed code you're using now, then. If you keep on assigning an object to a second one and then dispose of the second, you won't achieve much. Loop the collections with a `For` loop from `Collection.Count` to `0` and test the type of the current object without assigning it to anything. – Jimi Mar 26 '19 at 18:13
  • Tried this, still crashing. Private byte increase by 1MB with every Timer refresh. Dim ControlCollection As New List(Of HotListItem) For Each ctr As Control In Me.tabDeburring.Controls If TypeOf ctr Is HotListItem Then ControlCollection.Add(ctr) Next For i As Int16 = ControlCollection.Count - 1 To 0 Step -1 ControlCollection(i).Dispose() Next – Mitch Mar 26 '19 at 18:45
  • Do not post your code in the comments section. Update your question, clicking on the [edit](https://stackoverflow.com/posts/55362524/edit) link. Also, why do you keep adding control to other collections? You already have a `colletion: `tabDeburring.Controls`. That's the collection you need to iterate. You need to dispose of the objects in that collection. Not new ones. – Jimi Mar 26 '19 at 19:26
  • Thanks Jimi, new to this site. When the app refreshes the data, new controls need to be created or removed. The data on each control changes frequently. All that I am trying to do is destroy the controls on the tab page, and then create new ones with the updated data. I am having a hard time understanding why my original code does not work. – Mitch Mar 27 '19 at 13:41
  • I added revised code. This is still causing memory issues. The controls are still not being disposed. – Mitch Mar 27 '19 at 14:08

0 Answers0