UIAutomation,AutomationFocusChangedEventHandler和Mozilla Thunderbird 5.0的内存泄漏

问题描述:

 

很抱歉在这里提出Thunderbird,但我的C#4.0客户端框架示例应用程序存在问题,只是使用System.Windows.Automation.Automation注册了AutomationFocusChangedEventHandler.

sorry for coming up with Thunderbird here but I have a problem with my C# 4.0 client framework sample application just registering an AutomationFocusChangedEventHandler using System.Windows.Automation.Automation.

当我现在启动Mozilla Thunderbird 5.0并选择一封电子邮件时,每选择一封电子邮件,C#应用程序的非托管堆都会增长大约300kB.如果我大约每秒按下一次光标键以选择其他电子邮件,则堆会增长,并且成长和 永远不会再释放.

When I now start Mozilla Thunderbird 5.0 and select an email, the C# application's unmanaged heap grows about 300kB with each selected email. If I press the cursor key down about once a second for selecting other emails, the heap grows and grows and is never freed again.

我验证了在任务管理器的内存(私有工作集)"列中,转储了垃圾收集器的堆大小并使用SciTech .NET内存分析器对其进行了概要分析.

I verified that in task manager's column 'Memory (Private Working Set)', dumping the garbage collectors heap size and profiling it using SciTech .NET memory profiler.

 

这里是示例代码:

 

using System;
using System.Runtime.CompilerServices;
using System.Windows.Automation;
using System.Windows.Forms;

namespace MySimpleApp
{
 public class UiFocusHandler : ApplicationContext
 {
 public UiFocusHandler()
 {
 AddAutomationFocusChangedEventHandler();
 }

 [MethodImplAttribute(MethodImplOptions.NoInlining)]
 private void AddAutomationFocusChangedEventHandler()
 {
 Automation.AddAutomationFocusChangedEventHandler(
 new AutomationFocusChangedEventHandler(OnFocusChange));
 }

 [MethodImplAttribute(MethodImplOptions.NoInlining)]
 private void OnFocusChange(object src, AutomationFocusChangedEventArgs e)
 {
 }
 }

 static class Program
 {
 [STAThread]
 static void Main()
 {
 Application.Run(new UiFocusHandler());
 }
 }
}

对不起,马蒂亚斯,我以前从未听说过这种问题.因此,当您在电子邮件列表中移动焦点时,您会使用提供的简单代码片段在客户端看到意外的内存使用情况.
 
焦点更改的事件处理程序实际上似乎工作正常吗?也就是说,每当您选择新电子邮件时,就会呼叫您的处理程序. (出于好奇,如果关闭电子邮件应用程序,客户端应用程序的内存使用量会发生变化吗?)
 
运行AccEvent SDK工具来验证在选择电子邮件时生成的焦点更改事件是否符合您的预期可能会很有趣. (例如,一个焦点更改了每个选择的事件,以及与事件相关的数据 似乎正确.)
 
如果您使用的是本机Windows 7 UIA API,则会询问您是否使用设置为AutomationElementMode_None的AutomationElementMode的缓存请求创建焦点更改事件处理程序,是否看到类似的结果.这样,您可能已经缓存了 提供给焦点更改事件处理程序的数据,但不存在对provider元素的引用.默认情况下,会创建对provider元素的引用,因此该引用可能不会按预期稍后发布. .NET UIA API 确实允许使用AutomationElementMode为None来创建缓存请求,我不认为可以像Windows 7 IUIAutomation :: AddFocusChangedEventHandler()一样将缓存请求提供给.NET AddAutomationFocusChangedEventHandler().
 
不久前,我上传了一个示例C#应用程序,该应用程序使用Windows 7 UIA API跟踪焦点,网址为 http://code.msdn.microsoft.com/Windows-7-UI-Automation-6390614a .通过执行以下操作,可以设置焦点更改事件处理程序,使得不会保留对提供程序的引用:

Sorry Matthias, I’ve not heard of this sort of problem before. So you’re seeing unexpected memory usage on the client side using the simple snippet you provided, as focus is moved through the e-mail list.
 
Does the focus changed event handler actually seem to be working ok? That is, whenever you select a new e-mail, your handler gets called. (Out of curiosity, does the client app memory usage change if the e-mail app is closed?)
 
It might be interesting to run the AccEvent SDK tool to verify that the focus change events that get generated as you select the e-mails are as you’d expect. (For example, one focus changed event per selection, and the data associated with the events seems correct.)
 
If you were using the native Windows 7 UIA API, I’d ask whether you see similar results if you create the focus changed event handler with a cache request set with an AutomationElementMode of AutomationElementMode_None. By doing that, you could have cached data supplied to the focus changed event handler, but no reference to the provider element would exist. By default, a reference to the provider element is created, so perhaps that reference isn’t being released later as expected. While the .NET UIA API does allow a cache request to be created with an AutomationElementMode of None, I don’t think the cache request can be supplied to the .NET AddAutomationFocusChangedEventHandler() as it can with the Windows 7 IUIAutomation::AddFocusChangedEventHandler().
 
I uploaded a sample C# app a while ago which uses the Windows 7 UIA API to track focus, at http://code.msdn.microsoft.com/Windows-7-UI-Automation-6390614a. That sets up the focus changed event handler such that no reference to the provider is kept around, by doing this:

 

IUIAutomationCacheRequest cacheRequest = _automation.CreateCacheRequest();
cacheRequest.AddProperty(_propertyIdName);
cacheRequest.AddProperty(_propertyIdBoundingRectangle);

IUIAutomationCacheRequest cacheRequest = _automation.CreateCacheRequest();
cacheRequest.AddProperty(_propertyIdName);
cacheRequest.AddProperty(_propertyIdBoundingRectangle);

//以上属性是我们所需要的,因此我们不需要引用
//接收到事件时的源元素.
cacheRequest.AutomationElementMode = AutomationElementMode.AutomationElementMode_None;

// The above properties are all we'll need, so we have have no need for a reference
// to the source element when we receive the event.
cacheRequest.AutomationElementMode = AutomationElementMode.AutomationElementMode_None;

//现在设置事件处理程序.
_automation.AddFocusChangedEventHandler(cacheRequest,this);

// Now set up the event handler.
_automation.AddFocusChangedEventHandler(cacheRequest, this);

 

作为测试,您可以尝试将此示例应用程序与电子邮件应用程序一起使用,以查看其是否存在相同的内存问题.
 
谢谢
 
盖伊

As a test, you might try using this sample app with the e-mail app and see if it exhibits the same memory issues.
 
Thanks,
 
Guy