我使用工作线程来提取消息,并在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
到目前为止,我考虑了两个可能的问题并进行了一些测试:
对于第一个,我尝试在我的笔记本电脑中每1ms线一次提出消息事件,经过24小时测试,它仍然有效,也不例外。
由于第二个原因,我读了How to avoid leaking handles when invoking in UI from System.Threading.Timer?,并使用perfmon.exe来监控句柄是否泄漏,到目前为止似乎工作正常,GC无法收集未使用的句柄。
现在出于想法,我错过了其他问题吗?
答案 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()