I'm trying to get to grips with how Windows Forms applications manage memory allocation. I'll give you an illustration of the problem. Take this simple winforms app which is a main form with two buttons: one that opens a form containing some random data, and another button that closes all open forms (except the main form)

Code:
Public Class MainForm

    Private WithEvents _timer As System.Timers.Timer = New System.Timers.Timer()

    Private Sub UltraButton1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles UltraButton1.Click
        Try
            Dim frm As Form = New GridForm()
            frm.Show()

        Catch ex As Exception
            MessageBox.Show(ex.Message)
        End Try
        
    End Sub

    Private Sub _timer_Elapsed(ByVal sender As Object, ByVal e As System.Timers.ElapsedEventArgs) Handles _timer.Elapsed
        Dim bytesInUse As Long = GC.GetTotalMemory(False)
        Dim mbInUse As Double = Math.Round(bytesInUse / 1024 / 1024, 1)

        Dim msg As String = String.Format("Form Count: {0}        {1}       {2}MB       ({3} bytes)", (My.Application.OpenForms.Count - 1).ToString("000"), System.DateTime.Now.ToString("HH:mm:ss fff"), mbInUse.ToString("000"), bytesInUse.ToString("0000000000"))

        Debug.Print(msg)
    End Sub

    Private Sub MainForm_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
        _timer.Interval = 5000
        _timer.Enabled = True
    End Sub

    Private Sub UltraButton2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles UltraButton2.Click
        Try
            Dim closeForms As List(Of Form) = New List(Of Form)()

            For Each frm As Form In My.Application.OpenForms
                If frm.Name = "GridForm" Then
                    closeForms.Add(frm)
                End If
            Next

            For Each frm As Form In closeForms
                frm.Close()
                frm.Dispose()
            Next


        Catch ex As Exception
            MessageBox.Show(ex.Message)
        End Try
    End Sub
End Class





Public Class GridForm

    Private _randomData As List(Of RandomData) = Nothing
    
    Private Sub GridForm_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
        Try
            _randomData = RandomDataHelper.GetRandomData()

            Me.DataGridView1.DataSource = _randomData

        Catch ex As Exception

        End Try
    End Sub
End Class




Friend Class RandomData

    Private _guid As String
    Private _id As Integer

    Public Property MyGuid() As String
        Get
            Return _guid
        End Get
        Set(ByVal value As String)
            _guid = value
        End Set
    End Property

    Public Property Id() As Integer
        Get
            Return _id
        End Get
        Set(ByVal value As Integer)
            _id = value
        End Set
    End Property
End Class






Public Class RandomDataHelper

    Private Shared _randomData As List(Of RandomData) = Nothing

    Friend Shared Function GetRandomData() As List(Of RandomData)
        If _randomData Is Nothing Then
            _randomData = New List(Of RandomData)()
            For i As Integer = 1 To 100000
                _randomData.Add(New RandomData() With {.Id = i, .MyGuid = System.Guid.NewGuid().ToString()})
            Next
        End If

        Dim newList As List(Of RandomData) = New List(Of RandomData)()

        For Each rd In _randomData
            newList.Add(New RandomData() With {.Id = rd.Id, .MyGuid = rd.MyGuid})
        Next

        Return newList
    End Function

End Class


If you run this and click away opening lots of forms, 50 at a time, 100 at a time, and then closing them all, the memory goes up and down over time but gradually gets higher and higher, never returning to anything like its initial state. Now I assume part of this is the .NET runtime being clever and assuming that as the app needed a lot of memory previously, it will need more again and better to keep some allocated (I am running this on a machine with 4GB RAM).

This is the output


Code:
Form Count: 000        08:44:39 755       001MB       (0000813092 bytes)
Form Count: 001        08:44:44 728       017MB       (0017485136 bytes)
Form Count: 016        08:44:49 716       062MB       (0064453476 bytes)
Form Count: 016        08:44:54 705       062MB       (0064887652 bytes)
Form Count: 016        08:44:59 694       062MB       (0064887652 bytes)
Form Count: 016        08:45:04 682       062MB       (0064887652 bytes)
Form Count: 016        08:45:09 671       062MB       (0064887652 bytes)
Form Count: 016        08:45:14 660       062MB       (0064904036 bytes)
Form Count: 016        08:45:19 648       062MB       (0064904036 bytes)
Form Count: 016        08:45:24 637       062MB       (0065084260 bytes)
Form Count: 026        08:45:29 626       103MB       (0107992376 bytes)
Form Count: 049        08:45:34 614       178MB       (0186475920 bytes)
Form Count: 000        08:45:39 603       178MB       (0187032976 bytes)
Form Count: 006        08:45:44 594       202MB       (0212140692 bytes)
Form Count: 028        08:45:49 699       242MB       (0253800456 bytes)
Form Count: 063        08:45:54 585       389MB       (0407684876 bytes)
Form Count: 001        08:45:59 581       401MB       (0420033088 bytes)
Form Count: 019        08:46:04 576       268MB       (0280643940 bytes) -
Form Count: 029        08:46:09 572       313MB       (0328246272 bytes)
Form Count: 060        08:46:14 567       202MB       (0211634588 bytes) -
Form Count: 000        08:46:19 563       228MB       (0238579268 bytes)
Form Count: 021        08:46:24 559       303MB       (0317532092 bytes)
Form Count: 050        08:46:29 554       181MB       (0189643032 bytes) -
Form Count: 050        08:46:34 550       181MB       (0189643032 bytes)
Form Count: 007        08:46:39 592       205MB       (0214563092 bytes)
Form Count: 046        08:46:44 541       318MB       (0333827408 bytes)
Form Count: 000        08:46:49 537       335MB       (0350860716 bytes)
Form Count: 006        08:46:54 532       360MB       (0377380588 bytes)
Form Count: 041        08:46:59 528       293MB       (0306788368 bytes) -
Form Count: 049        08:47:04 524       329MB       (0344529752 bytes)
Form Count: 049        08:47:09 519       329MB       (0344529752 bytes)
Form Count: 049        08:47:14 515       329MB       (0344529752 bytes)
Form Count: 000        08:47:19 510       329MB       (0345054040 bytes)
Form Count: 000        08:47:24 506       329MB       (0345070424 bytes)
Form Count: 000        08:47:29 502       329MB       (0345095000 bytes)
Form Count: 000        08:47:34 497       329MB       (0345095000 bytes)
Form Count: 019        08:47:39 524       404MB       (0423631984 bytes)
Form Count: 049        08:47:44 489       166MB       (0173639576 bytes) -
Form Count: 049        08:47:49 484       166MB       (0173655960 bytes)
Form Count: 000        08:47:54 480       160MB       (0168018476 bytes)
Form Count: 000        08:47:59 475       160MB       (0168018476 bytes)
Form Count: 013        08:48:04 471       215MB       (0225774536 bytes)
Form Count: 050        08:48:09 623       306MB       (0320518980 bytes)
Form Count: 090        08:48:14 525       474MB       (0496950512 bytes)
Form Count: 099        08:48:19 458       514MB       (0538941444 bytes)
Form Count: 099        08:48:24 453       514MB       (0538941444 bytes)
Form Count: 099        08:48:29 449       514MB       (0538941444 bytes)
Form Count: 099        08:48:34 445       514MB       (0538949636 bytes)
Form Count: 099        08:48:39 440       514MB       (0538949636 bytes)
Form Count: 099        08:48:44 436       514MB       (0539039748 bytes)
Form Count: 000        08:48:49 432       515MB       (0540022788 bytes)
Form Count: 012        08:48:54 427       565MB       (0592271776 bytes)
Form Count: 049        08:48:59 423       473MB       (0496036112 bytes) -
Form Count: 088        08:49:04 418       646MB       (0677261468 bytes)
Form Count: 099        08:49:09 414       691MB       (0725020668 bytes)
Form Count: 099        08:49:14 410       691MB       (0725028860 bytes)
Form Count: 099        08:49:19 405       691MB       (0725028860 bytes)
Form Count: 099        08:49:24 401       691MB       (0725028860 bytes)
Form Count: 099        08:49:29 396       691MB       (0725028860 bytes)
Form Count: 033        08:49:34 392       692MB       (0725710488 bytes)
Form Count: 000        08:49:39 388       692MB       (0726046360 bytes)
Form Count: 005        08:49:44 383       316MB       (0331798056 bytes) -
Form Count: 005        08:49:49 379       318MB       (0333050676 bytes)
Form Count: 005        08:49:54 375       318MB       (0333050676 bytes)
Form Count: 030        08:49:59 370       101MB       (0106193620 bytes) --
Form Count: 063        08:50:04 506       200MB       (0209653496 bytes)
Form Count: 065        08:50:09 361       213MB       (0223073476 bytes)
Form Count: 065        08:50:14 357       213MB       (0223081668 bytes)
Form Count: 000        08:50:19 353       212MB       (0222580224 bytes)
Form Count: 004        08:50:24 348       230MB       (0241493684 bytes)
Form Count: 005        08:50:29 344       250MB       (0262433028 bytes)
Form Count: 005        08:50:34 339       250MB       (0262433028 bytes)
Form Count: 005        08:50:39 335       250MB       (0262433028 bytes)
Form Count: 005        08:50:44 332       250MB       (0262441220 bytes)
Form Count: 005        08:50:49 330       250MB       (0262441220 bytes)
Form Count: 005        08:50:54 328       250MB       (0262449412 bytes)
Form Count: 035        08:50:59 326       375MB       (0393604792 bytes)
Form Count: 070        08:51:04 324       443MB       (0463951896 bytes)
Form Count: 098        08:51:09 338       558MB       (0585160608 bytes)
Form Count: 000        08:51:14 336       564MB       (0591128768 bytes)
Form Count: 003        08:51:19 334       576MB       (0604198604 bytes)
Form Count: 003        08:51:24 333       588MB       (0616855512 bytes)
Form Count: 000        08:51:29 331       601MB       (0629999648 bytes)
Form Count: 020        08:51:34 329       683MB       (0716641424 bytes)
Form Count: 005        08:51:39 327       704MB       (0738295324 bytes)
Form Count: 013        08:51:44 372       766MB       (0802846820 bytes)
Form Count: 048        08:51:49 323       552MB       (0578560104 bytes) -
Form Count: 001        08:51:54 322       565MB       (0592206272 bytes)
Form Count: 005        08:51:59 320       581MB       (0609027444 bytes)
Form Count: 009        08:52:04 318       598MB       (0627505656 bytes)
Form Count: 004        08:52:09 316       617MB       (0646774500 bytes)
Form Count: 004        08:52:14 314       617MB       (0646774500 bytes)
Form Count: 025        08:52:19 313       253MB       (0265532620 bytes) - 
Form Count: 000        08:52:24 311       254MB       (0265835724 bytes)
Form Count: 000        08:52:29 309       254MB       (0265835724 bytes)
Form Count: 000        08:52:34 307       254MB       (0265876684 bytes)
Form Count: 000        08:52:39 305       254MB       (0265876684 bytes)

You can see the memory dropping at intervals (I've marked some of them above) which is good but it still slowly has a minimum that creeps up and up.

This is a very basic illustration of a much bigger production issue with a huge application with 100,000s lines of code and users that keep the app open all day. Over time they open and close a lot of forms and the memory creeps up.

Is there any way to force the allocation down? I know I can force GC but this won't do anything as it's the memory post-GC that is remaining high as far as I can see.

This isn't a problem with references as far as I can see because I have spent some time experimenting with just one form in the main application opening and closing it and there are no references after it is closed and disposed and yet the memory still creeps up in a similar way to that logged above. Also if it was a problem with references, I'm not sure how that would explain my test app above.

Any help or advice on what to use to troubleshoot greatly received.