Das Speichern eines FixedDocuments in einer XPS-Datei führt zu einem Speicherleck

8

Ich habe einen .NET Windows-Dienst erstellt, der bestimmte Aktionen ausführt und Berichte generiert. Diese Berichte sind XPS-Dokumente, die ich in einem bestimmten Verzeichnis speichern kann.

Wenn ich mit WPF vertraut bin, habe ich die Art und Weise gewählt, wie ich die Berichte erstellen möchte, indem ich ein System.Windows.Documents.FixedDocument instanziiere und FixedPage -Objekte mit dem Inhalt nach Bedarf hinzufüge.

Mein Problem ist, dass die Speicherbelegung des Dienstes im Laufe der Zeit hoch und runter geht.

Zuerst habe ich meinen Code gründlich durchgesehen, um sicherzustellen, dass alle verfügbaren Objekte entsorgt wurden, und andere offensichtliche Speicherleck-Kandidaten, aber ich hatte immer noch das Problem. Ich habe dann den CLR Profiler verwendet, um die Speichernutzung des Dienstes im Detail zu betrachten.

Ich habe festgestellt, dass, während der Dienst diese FixedDocument -Berichte generiert und sie als XPS-Dateien speichert, alle verschiedenen UI-Elemente, die FixedDocument -Objekten zugeordnet sind ( Dispatcher , FixedPage , UIElementCollection , Visual usw.) bleiben in Erinnerung.

Dies scheint nicht der Fall zu sein, wenn ich in meinen WPF-Apps dasselbe mache. Daher ist meine Vermutung, dass es etwas mit dem WPF-UI-Dispatcher-Modell zu tun hat, das außerhalb einer WPF-App verwendet wird.

Wie kann ich meine FixedDocument -Objekte "entsorgen", wenn Sie sie in einem Dienst wie diesem verwenden (oder außerhalb einer WPF-App im Allgemeinen)?

======== EDIT =========

OK, ich habe festgestellt, dass mein Speicherverlust nicht speziell mit dem Erstellen / Füllen eines FixedDocuments zu tun hat. Wenn ich dies tue, aber nicht wirklich als XPS auf die Festplatte speichere, passiert das Speicherleck nicht. Also, mein Problem muss mit dem Speichern als XPS-Datei zu tun haben.

Hier ist mein Code:

%Vor%

Was ich versucht habe:

  • Manuelle Speicherbereinigung
  • Aufruf von UpdateLayout() auf jeder Seite von myFixedDocument vor dem Paginator (wie in der Antwort unten vorgeschlagen) - Ich habe auch versucht, myFixedDocument direkt in Write() , d. h. nicht den Paginator
  • zu übergeben
  • Diese Codezeilen in einen eigenen Thread einfügen und Dispatcher manuell beenden

Immer noch kein Glück.

========== Abhilfe ==========

Indem Sie den obigen Code mithilfe der allgemeinen Methode, die im Beispiel unter Ссылка dargestellt wird, in seine eigene AppDomain einbinden , der Speicherverlust wirkt sich nicht mehr auf meinen Dienst aus (ich sage "betrifft das nicht mehr", weil es immer noch passiert, aber wenn die AppDomain entladen wird, werden alle ausgelaufenen Ressourcen damit entladen).

Ich wäre immer noch scharf darauf, eine echte Lösung zu sehen.

(Bei einer diesbezüglichen Anmerkung verursachte die Verwendung einer separaten Anwendungsdomäne einen Speicherverlust in der PDFSharp-Komponente, die ich verwendete, um bestimmte XPS-Dateien in PDF-Dateien umzuwandeln.) PDFsharp verwendet einen globalen Zeichensatzcache, der unter normalen Umständen nicht funktioniert Der Cache wuchs und wuchs, nachdem ich diese AppDomains verwendet habe. Ich habe den PDFSharp-Quellcode bearbeitet, damit ich manuell FontDataStock und FontDataStock löschen konnte, um das Problem zu lösen.)

========== LÖSUNG ===========

Siehe meine Antwort unten für die endgültige Lösung.

    
Ross 05.01.2012, 12:24
quelle

2 Antworten

15

Ich habe schließlich eine Antwort gefunden, die aus zwei Teilen besteht.

Erstens, nachdem ich mein XPS-Dokument auf dem Datenträger gespeichert und das XpsDocument geschlossen / entsorgt habe, führe ich die folgende Codezeile aus:

%Vor%

Dies löscht alle Dispatcher Objekte, die im Speicher hängen.

Während das obige die meisten Speicherprobleme aussortiert, bemerkte ich, dass es noch FixedPage-Objekte zusammen mit anderen noch im Speicher befindlichen UI-Objekten gab. Manuelles Löschen meines FixedDcounts scheint sie los zu werden:

%Vor%     
Ross 11.01.2012, 22:57
quelle
0

Aus dies sieht es wie Sie aus muss .UpdateLayout () mindestens einmal aufrufen, um Speicherverlust zu vermeiden

    
Nat 05.01.2012 12:31
quelle