Control.invoke时的OutOfMemory异常

时间:2015-12-25 08:23:10

标签: vb.net multithreading winforms memory-leaks

我使用工作线程来提取消息,并在UI线程上使用事件处理程序来调用Control.Invoke以在RichTextBox上显示它们。 现在发现在目标机器上连续运行12小时后会产生异常。

日志显示:

  System.Windows.Forms.Control.MarshaledInvoke(Control caller,Delegate方法,Object [] args,布尔同步)时出现System.OutOfMemoryException

以下是我在主表单中的代码的一部分:

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

到目前为止,我考虑了两个可能的问题并进行了一些测试:

  1. 删除TextBox上第一行的方法不合适。
  2. 有一些关于Control.Invoke的副作用,我以前不知道。
  3. 对于第一个,我尝试在我的笔记本电脑中每1ms线一次提出消息事件,经过24小时测试,它仍然有效,也不例外。

    由于第二个原因,我读了How to avoid leaking handles when invoking in UI from System.Threading.Timer?,并使用perfmon.exe来监控句柄是否泄漏,到目前为止似乎工作正常,GC无法收集未使用的句柄。

    现在出于想法,我错过了其他问题吗?

1 个答案:

答案 0 :(得分:0)

发现此命令存在缺陷:

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

如果通过参数 e 出现多行消息,它将仅删除每个事件引发的最开始的单行,这样RichTextBox的堆使用量可能会在这种情况下继续增长,当然还有最终可能会出现 OutOfMemory

documentation中,找到了在RichTextBox上保留固定行的有用替代方法,它可以解决这个问题。

RichTextBoxHistory.Lines = RichTextBoxHistory.Lines.Skip(RichTextBoxHistory.Lines.Length - 64).ToArray()