0

I use a working thread to pump up messages , and use a event handler on UI thread to call Control.Invoke to show them on the RichTextBox. Now found it would generate exception after 12 hours continuous running on target machine.

Log showed that:

System.OutOfMemoryException when System.Windows.Forms.Control.MarshaledInvoke(Control caller, Delegate method, Object[] args, Boolean synchronous)

And here's part of my codes in Main Form:

Dim __lastMessage As String = ""    
Private Sub historyMessageHandler(ByVal sender As messageHandler, ByVal e As String) Handles messengerReference.MessagePoped

    'prevent invoking after form closed
    If (Me.IsDisposed) Then
        Exit Sub
    End If

    Dim __thisMessage As String = e

    If (__lastMessage <> __thisMessage) Then
        '---------------------------
        ' Once this message is not equal to last mesage  , post on the history panel
        '---------------------------
        Me.Invoke(Sub()
                      RichTextBoxHistory.Text += (e & vbCrLf)
                      '-------------------------------------------
                      '    Discard oldest message if count reached to prevent buffer overload
                      '-------------------------------------------
                      If (RichTextBoxHistory.Lines.Length > 64) Then
                           RichTextBoxHistory.Text = String.Join(vbCrLf,RichTextBoxHistory.Lines, 1, RichTextBoxHistory.Lines.Count - 1)
                      End If
                      '----------------------
                      ' keep scoll on bottom
                      '---------------------
                  textBox.SelectionStart = textBox.Text.Length
                  textBox.ScrollToCaret()

                  End Sub)
    Else
        '-----------------------
        'redundant message found , no need to show
        '-----------------------

    End If

    __lastMessage = __thisMessage  'memorize last message
End Sub

Until now i considered two possible issues and did some tests:

  1. The way to remove first line on TextBox is not appropriate.
  2. There's some side-effect about Control.Invoke i don't know before.

For the first one , i tried to raise message event once a line per 1ms in my laptop, after 24 hours testing , it still works , no exception.

For the second reason , i read How to avoid leaking handles when invoking in UI from System.Threading.Timer? , and use perfmon.exe to monitor if handle leaks , it seems works fine so far, unused handles was collected by GC for sure.

Out of ideas now , is there other issue i missed?

Community
  • 1
  • 1
Ju-Hsien Lai
  • 643
  • 7
  • 14

1 Answers1

0

Found a defect on this command:

RichTextBoxHistory.Text =
String.Join(vbCrLf,RichTextBoxHistory.Lines, 1,
RichTextBoxHistory.Lines.Count - 1)

If there's multi line message coming via argument e, it would delete only the very beginning single line per event raised , so that the heap usage of RichTextBox may keep growing on this situation , of course there's possible to occurs OutOfMemory in the end.

In this post, found the useful alternative calling to keeps fixed lines on RichTextBox, it can solve this problem.

RichTextBoxHistory.Lines = RichTextBoxHistory.Lines.Skip(RichTextBoxHistory.Lines.Length - 64).ToArray()
Community
  • 1
  • 1
Ju-Hsien Lai
  • 643
  • 7
  • 14