【问题标题】:UIAutomation Memory IssueUIAutomation 内存问题
【发布时间】:2013-09-20 20:17:10
【问题描述】:

我有一个简单的 WPF 程序,它只有一个按钮,没有事件处理逻辑。然后,我使用 UIAutomation 框架连续多次单击该按钮。最后,我看看 WPF 程序使用的内存,它似乎越来越大。

有谁知道为什么会这样,以及如何防止这种情况发生?

这是一个简单的 WPF 程序(后面的代码中没有任何内容):

<Window x:Class="SimpleApplication.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="Simple Application"
        AutomationProperties.AutomationId="Simple Application"
        Height="350" Width="525">
    <Grid>
        <Button AutomationProperties.AutomationId="button" Height="50" Width="100">Click Me</Button>
    </Grid>
</Window>

这是 UIAutomation 测试程序:

class Program
{
    static void Main(string[] args)
    {
        string appPath = @"..\..\..\SimpleApplication\bin\Debug\SimpleApplication.exe";
        string winAutoId = "Simple Application";
        string buttonAutoId = "button";

        using (Process process = Process.Start(new ProcessStartInfo(appPath)))
        {
            Thread.Sleep(TimeSpan.FromSeconds(1));

            AutomationElement winElement = AutomationElement.RootElement.FindFirst(TreeScope.Children, new PropertyCondition(AutomationElement.AutomationIdProperty, winAutoId));

            for (int i = 0; i < 1001; i++)
            {
                AutomationElement buttonElement = winElement.FindFirst(TreeScope.Descendants, new PropertyCondition(AutomationElement.AutomationIdProperty, buttonAutoId));

                InvokePattern invokePattern = (InvokePattern)buttonElement.GetCurrentPattern(InvokePattern.Pattern);
                invokePattern.Invoke();

                process.Refresh();
                long totalMemory = process.WorkingSet64 + process.PagedMemorySize64;

                if (i % 100 == 0)
                {
                    Console.WriteLine("Memory = {0} MB", ((double)totalMemory) / (1024 * 1024));
                }
            }

            WindowPattern windowPattern = (WindowPattern)winElement.GetCurrentPattern(WindowPattern.Pattern);
            windowPattern.Close();
        }

        Console.WriteLine();
        Console.WriteLine("Press Enter to Continue...");
        Console.ReadLine();
    }
}

这是我机器上程序的结果:

Memory = 38.20703125 MB
Memory = 42.9296875 MB
Memory = 45.00390625 MB
Memory = 47.04296875 MB
Memory = 51.9296875 MB
Memory = 52.2890625 MB
Memory = 52.41015625 MB
Memory = 55.70703125 MB
Memory = 55.70703125 MB
Memory = 57.21484375 MB
Memory = 59.09375 MB

使用 .NET Memory Profiler 查看它,WPF 应用程序中出现的新对象来自 System.Threading 命名空间。当我自己运行 WPF 程序并用鼠标单击按钮时,这些对象不会出现。

更新:

我尝试使用 Visual Studio 的 CodedUI 进行类似的测试,同样的 8 个对象在这种情况下似乎也泄漏了。似乎泄漏的对象是:

System.Threading.CancellationTokenSource
System.Threading.TimerQueueTimer
System.Threading.SparselyPopulatedArray<CancellationCallbackInfo>[]
System.Threading.Timer
System.Threading.TimerHolder
System.Threading.SparselyPopulatedArray<CancellationCallbackInfo>
System.Threading.SparselyPopulatedArrayFragment<CancellationCallbackInfo>
System.Threading.CancellationCallbackInfo[]

我还向 Microsoft 提交了一个错误:

http://connect.microsoft.com/VisualStudio/feedback/details/801209/uiautomation-memory-issue

【问题讨论】:

    标签: c# wpf memory-leaks ui-automation


    【解决方案1】:

    尽量在for循环外声明buttonElement、invokePattern等对象。

    【讨论】:

    • 这似乎减缓了内存增长,但并没有阻止它。现在它以大约 53 MB 而不是 60 MB 结束。
    【解决方案2】:

    在与 Microsoft 客户支持交谈后,我们找到了问题的答案。在内部,WPF 给自己三分钟时间来响应 UI 自动化事件。为此,它启动了一个计时器。看来即使事件立即得到响应,计时器也不会在三分钟结束后消失。

    因此,解决此问题的方法是等到计时器到期,然后执行 GC.Collect。然后内存问题就会消失。不是一个很好的解决方案,但它适用于我们的情况。

    【讨论】:

    • 一些研究:referencesource.microsoft.com/… 然后检查 Element.Invoke 在 SynchronizedInputAdaptor(ISynchronizedInputProvider)上调用取消需要 3 分钟的超时时间。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-09-22
    • 2014-12-19
    • 2021-10-06
    • 2015-05-03
    • 2012-07-22
    • 2016-03-25
    相关资源
    最近更新 更多