为什么这个.net UIAutomation应用程序泄漏/汇集?

时间:2010-06-29 21:08:24

标签: c# .net vb.net memory-leaks ui-automation

我有一个使用.net UIAutomation的应用程序,它最终会耗尽内存而崩溃只是监视正在显示和关闭的窗口。似乎更容易在VB中显示这个比C#更多,但无论哪种方式都是相同的。它似乎是底层代理对象中的泄漏/池。大部分内存未显示为使用.net内存。

关于如何让它停止泄漏并仍然监控StructureChangedEvents的任何想法?

Imports System.Windows.Automation
Public Class Form1

Delegate Sub AddListCallback(ByVal Text As String)
Dim UIAeventHandler As StructureChangedEventHandler

Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
    BtnStartStop.Text = "Stop"
    Subscribe()
End Sub

Private Sub BtnStartStop_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles BtnStartStop.Click
    If "Start" = BtnStartStop.Text Then
        BtnStartStop.Text = "Stop"
        Subscribe()
    Else
        BtnStartStop.Text = "Start"
        Unsubscribe()
        lbEvents.Items.Clear()
        GC.GetTotalMemory(True)
    End If
End Sub

Public Sub Subscribe()
    UIAeventHandler = New StructureChangedEventHandler(AddressOf OnUIAutomationEvent)
    Automation.AddStructureChangedEventHandler(AutomationElement.RootElement, TreeScope.Descendants, UIAeventHandler)
End Sub 

Public Sub Unsubscribe()
    Automation.RemoveStructureChangedEventHandler(AutomationElement.RootElement, UIAeventHandler)
End Sub

''' <summary>
''' AutomationEventHandler delegate.
''' </summary>
''' <param name="src">Object that raised the event.</param>
''' <param name="e">Event arguments.</param>
Private Sub OnUIAutomationEvent(ByVal src As Object, ByVal e As StructureChangedEventArgs)
    ' Make sure the element still exists. Elements such as tooltips can disappear
    ' before the event is processed.  
    If e.StructureChangeType = StructureChangeType.ChildrenInvalidated Then
        Exit Sub
    End If
    Dim sourceElement As AutomationElement
    Try
        sourceElement = DirectCast(src, AutomationElement)
    Catch ex As ElementNotAvailableException
        Exit Sub
    End Try
    ' TODO Handle any other events that have been subscribed to.
    Console.WriteLine( "Element : """ & sourceElement.Current.LocalizedControlType & """ """ & sourceElement.Current.Name _
       & """ Struct Change Type : " & [Enum].GetName(GetType(StructureChangeType), e.StructureChangeType) _
       & " Runtime ID : " & getString(e.GetRuntimeId()))
End Sub 

Private Function getString(ByVal ints As Integer()) As String
    getString = ""
    For Each i As Integer In ints
        getString = getString & " " & i.ToString
    Next
End Function
End Class

2 个答案:

答案 0 :(得分:1)

@jaws是正确的(还有一些其他事情要考虑),但是它在C#中。对于VB,您需要执行以下操作:

Automation.RemoveStructureChangedEventHandler(AutomationElement.RootElement, UIAeventHandler)
UIAeventHandler = Nothing

因为没有将UIAeventHandler设置为空,所以当您取消订阅时,将重新分配已经在内存中的事件处理程序。

考虑一下。请注意,当表单加载时您正在调用订阅,并使用按钮来订阅/取消订阅。然后,在加载表单时,将分配事件处理程序,并且该事件处理程序应该可以正常工作,即直到您按该顺序取消订阅/订阅为止。如果没有将UIAeventHandler设置为Nothing,则会导致内存泄漏,因为然后在订阅时将UIAeventHandler设置为NEW实例。因此,您也可以按照@jaws的建议执行以下操作:

Imports System.Windows.Automation
Public Class Form1
    Dim UIAeventHandler as StructureChangedEventHandler

    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        BtnStartStop.Text = "Stop"
        Subscribe()
    End Sub

    Public Sub Subscribe()
        UIAeventHandler = New StructureChangedEventHandler(AddressOf OnUIAutomationEvent)
        Automation.AddStructureChangedEventHandler(AutomationElement.RootElement, TreeScope.Descendants, UIAeventHandler)
    End Sub 

    Public Sub Unsubscribe()
        Automation.RemoveStructureChangedEventHandler(AutomationElement.RootElement, UIAeventHandler)
        UIAeventHandler = Nothing   'Here is the Important part!
    End Sub

End Class

答案 1 :(得分:0)

取消订阅时我会做这样的事情:

Automation.RemoveAllEventHandlers();
UIAeventHandler = null;
只要你有一个AutomationEventHandler对象,UIAutomation就会保留一些线程。它对我来说几乎是一个黑盒子,但上面已经修复了我所有的问题。