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.


Reply With Quote



always alive
!!!!
