2013-09-16 9 views
8

Ich habe ein einfaches WPF-Programm, das nur eine einzige Schaltfläche ohne Ereignisbehandlungslogik hat. Ich verwende dann das UIAutomation-Framework, um diese Schaltfläche mehrmals hintereinander anzuklicken. Abschließend betrachte ich die Speicherkapazität des WPF-Programms und es scheint zu wachsen und zu wachsen.UIAutomation Memory Problem

Wer weiß, warum das der Fall ist und wie ich das verhindern kann?

Hier ist das einfache WPF-Programm (nichts in der Code-behind):

<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> 

Hier das Programm UIAutomation Tests:

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(); 
    } 
} 

Hier sind die Ergebnisse aus dem Programm auf meinem Rechner:

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 

Betrachten Sie es mit dem .NET Memory Profiler, die neuen Objekte, die erscheinen i Die WPF-Anwendung stammt aus dem System.Threading-Namespace. Wenn ich das WPF-Programm selbst ausführe und auf den Knopf mit der Maus klicke, erscheinen diese Objekte nicht.

UPDATE:

Ich habe versucht, einen ähnlichen Test tut Visual Studio CodedUI verwenden und die gleichen 8 Objekte erschienen auch in dieser Situation zu lecken. Die Objekte, die lecken erscheinen, sind:

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[] 

Ich habe auch einen Fehler zu Microsoft vorgelegt:

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

Antwort

4

Nachdem wir mit dem Microsoft-Kundensupport gesprochen haben, haben wir die Antwort auf das Problem gefunden. Intern gibt sich WPF drei Minuten Zeit, um auf ein UI Automation-Ereignis zu reagieren. Um dies zu tun, startet es einen Timer. Es scheint, dass selbst wenn auf das Ereignis sofort reagiert wird, der Timer erst nach Ablauf der drei Minuten verschwindet.

So die Problemumgehung für das Problem ist, bis der Timer abläuft und dann eine GC.Collect durchführen. Dann wird das Speicherproblem verschwinden. Keine großartige Lösung, aber es funktioniert für unsere Situation.

0

Versuchen Sie, die Objekte wie buttonElement und InvokePattern außerhalb der for-Schleife zu erklären.

+0

Das schien das Speicherwachstum zu verlangsamen, aber nicht zu stoppen. Jetzt endet es bei etwa 53 MB statt 60 MB. – user2784456