FlowDocument Speicherproblem in C #

8

Ich versuche derzeit, ein Problem mit der Freigabe von FlowDocument-Ressourcen zu lösen. Ich lade eine RTF-Datei und lege sie in ein FlowDocument mit TextRange.Load. Ich habe bemerkt, dass, nachdem es dies getan hat, es diese Ressourcen festhält und GC es nicht sammelt. Ich habe einen Speicherprofiler laufen lassen und habe gesehen, dass das wahr ist. Ich habe es auch darauf beschränkt, dass ich den rtf tatsächlich in das FlowDocument geladen habe. Wenn ich das nicht mache, ist alles in Ordnung. Also ich weiß, das ist das Problem.

Ich hoffe auf eine Anleitung, wie ich dieses Problem lösen kann. Hier ist der Code, der das rtf und alles lädt. Ich habe den ganzen anderen Code kommentiert und sogar in seinen eigenen Bereich gesetzt und GC.Collect () ausprobiert. Jede Hilfe wird sehr geschätzt.

BEARBEITEN: Hier ist mein Code im Moment vollständig. Ich habe alles andere außer dem Nötigsten herausgenommen, um es zum Laufen zu bringen. Das Problem besteht immer noch. Wie Sie sehen können, werden FlowDocument und TextRange nirgendwo anders referenziert.

%Vor%

Ich fand diesen Beitrag , was ich hoffte, würde mir helfen, mein Problem zu lösen, aber ich hatte kein Glück damit. Jede Art von Hilfe wird sehr geschätzt. Danke.

EDIT: Ich denke, ich sollte den Hauptweg erwähnen, den ich hier überprüfe. Ich habe den Windows Task-Manager geöffnet und beobachte die Speicherauslastung meines Anwendungsprozesses. Wenn ich den oben genannten Code ausführe, geht die Anwendung von 40.000K auf 70.000K während der TextRange.Load () (dies ist eine große 400 Seiten RTF) und sobald es fertig ist fällt es auf 61.000K und bleibt dort. Ich gehe davon aus, dass es auf 40.000 K fallen würde oder zumindest sehr nahe daran.

Wie ich bereits erwähnt habe, habe ich einen Speicherprofiler verwendet und gesehen, dass es viele Absätze, Run..ect, gab. Objekte bleiben danach lebendig.

    
Jasson 04.06.2009, 20:44
quelle

8 Antworten

6

Wenn ich bestätigt habe, dass ein Speicherleck vorliegt, würde ich Folgendes tun, um das Problem zu beheben:

  1. Installieren Sie die Debugging-Tools für Windows von Ссылка
  2. Starten Sie Windbg aus dem Installationsverzeichnis.
  3. Starten Sie Ihre Anwendung und führen Sie die Operationen durch, die Speicher verlieren.
  4. Hängen Sie Windbg an Ihre Anwendung an (F6).
  5. Geben Sie .loadby sos mscorwks ein
  6. Geben Sie !dumpheap -type FlowDocument ein
  7. Überprüfen Sie das Ergebnis des obigen Befehls. Wenn Sie mehrere FlowDocuments sehen, führen Sie für jeden Wert der ersten Spalte (die die Adresse enthält)
  8. aus

Geben Sie !gcroot <value of first column>

ein

Das sollte dir zeigen, wer an der Referenz festhält.

    
Senthil Kumar 23.06.2009 04:26
quelle
3

Wir hatten ein ähnliches Problem, bei dem wir Flow-Dokumente in verschiedenen Threads erstellten. Ich bemerkte im Speicher-Profiler, dass Objekte immer noch da waren.

Soweit ich weiß, wie in diesem Artikel beschrieben link

"Wenn ein FlowDocument erstellt wird, werden dafür auch relativ teure Formatierungskontextobjekte in seinem StructuralCache erstellt. Wenn Sie mehrere FlowDocs in einer engen Schleife erstellen, wird für jedes FlowDoc ein StructuralCache erstellt. Lassen Sie sich Gc.Collect im Ende der Schleife, in der Hoffnung, etwas Speicher wiederherzustellen. Mit dem Finalizer von ConstructionCache wird dieser Formatierungskontext freigegeben, jedoch nicht sofort. Der Finalizer plant effektiv eine Operation zur Freigabe von Kontexten in DispatcherPriority.Background. "

Bis die Dispatcher-Operationen abgeschlossen sind, befindet sich das Flow-Dokument also im Speicher. Die Idee besteht also darin, die Dispatcher-Operationen abzuschließen.

Wenn Sie sich in einem Thread befinden, in dem der Dispatcher gerade ausgeführt wird, versuchen Sie den folgenden Code. Dadurch werden alle Vorgänge in der Warteschlange abgeschlossen, da SystemIdle die niedrigste Priorität hat:

%Vor%

Wenn Sie sich in einem Thread befinden, in dem der Dispatcher nicht läuft, da in meinem Fall nur ein einzelnes Ablaufdokument im Thread erstellt wurde, habe ich versucht, etwas wie:

%Vor%

Dies wird am Ende ein Herunterfahren in die Warteschlange stellen und dann den Dispatcher dazu veranlassen, das FlowDocument zu bereinigen und dann wird es den Dispatcher herunterfahren.

    
Nitin Midha 12.11.2010 15:34
quelle
1

FlowDocument verwendet System.Windows.Threading.Dispatcher, um alle Ressourcen freizugeben. Finalizer werden nicht verwendet, da Finalizer den aktuellen Thread blockiert, bis alle Ressourcen frei sind. So kann der Benutzer einige UI-Freezings und so weiter sehen. Dispatcher werden im Hintergrund-Thread ausgeführt und haben weniger Auswirkungen auf die Benutzeroberfläche.
Also Aufruf von GC.WaitForPendingFinalizers (); hat keinen Einfluss darauf. Sie müssen nur etwas Code hinzufügen, um zu warten und den Dispatchern zu erlauben, ihre Arbeit zu beenden. Versuchen Sie einfach etwas wie Thread.CurrentThread.Sleep (2000 / * 2 Sekunden * /);

hinzuzufügen

BEARBEITEN: Es scheint mir, dass Sie dieses Problem beim Debuggen einiger Anwendungen gefunden haben. Ich habe den folgenden sehr einfachen Testfall (Konsolenprogramm) geschrieben:

%Vor%

Ich habe versucht, das Problem zu reproduzieren. Ich lief es mehrmals und es funktionierte perfekt - es gab keine Lecks (ca. 3,2Kb die ganze Zeit und 36 Griffe). Ich konnte es nicht reproduzieren, bis ich dieses Programm im Debug-Modus in der VS (nur f5 statt Strg + f5) ausführen. Ich erhielt zu Beginn 20,5Kb, nach dem Laden 31,7Kb und vor GC GC und 31Kb nach GC. Es ähnelt Ihren Ergebnissen.
Also, könnten Sie bitte versuchen, dieses Problem im Freigabemodus nicht unter dem VS zu reproduzieren?

    
zihotki 05.06.2009 00:09
quelle
1

Ich hatte vorher # 7 gemacht. Es war das erste Mal, dass ich Windbg benutzt habe und ich wusste nicht, was ich mit der Adresse machen sollte, um die Referenzen zu finden. Hier ist, was ich habe.

%Vor%

(Ich habe es in einen Codeblock geschrieben, um das Lesen zu erleichtern). Das ist, nachdem ich das Fenster geschlossen habe. Es sieht also so aus, als ob es von einigen Dingen referenziert wird. Jetzt, wo ich weiß, wie gehe ich diese Referenzen frei, damit sie das FlowDocument freigeben können.

Danke für Ihre Hilfe. Ich fühle mich, als würde ich endlich etwas an Boden gewinnen.

    
Jasson 24.06.2009 03:04
quelle
0

Stellen Sie sicher, dass das Parent des FlowDocument nicht herumhängt, siehe hier . "Durch das Instanziieren eines FlowDocuments wird automatisch ein übergeordnetes FlowDocumentPageViewer-Objekt erstellt, das den Inhalt hostet." Wenn dieses Steuerelement herumhängt, könnte es die Ursache Ihres Problems sein.

    
SpaceghostAli 04.06.2009 21:01
quelle
0

GC.Collect() selbst wird nicht alles sammeln, Sie müssen ausführen:

%Vor%

Außerdem habe ich festgestellt, dass die Laufzeit den gesammelten Speicher nicht immer sofort freigibt. Sie sollten die tatsächliche Größe des Heapspeichers überprüfen, anstatt sich auf den Task-Manager zu verlassen.

    
Eric 14.06.2009 04:37
quelle
0

Überlegen Sie, ob Sie das Dateihandle freigeben. Denken Sie auch daran, die "using" -Anweisung zu verwenden, anstatt IDisposable.Dispose aufzurufen (kein Wortspiel beabsichtigt).

    
GregC 14.06.2009 20:50
quelle
0

Ich habe versucht, Ihr Problem zu reproduzieren, aber es passiert nicht auf meinem Computer.

Der Task-Manager zeigt die Größe des Arbeitssatzes an, wobei es sich nicht um eine genaue Darstellung der Speicherbelegung eines Programms handelt. Verwenden Sie stattdessen perfmon.

  1. Start - & gt; Ausführen - & gt; perfmon.msc
  2. Fügen Sie .NET CLR-Speicher / # Bytes in allen Heaps für Ihre Anwendung hinzu

Wiederholen Sie nun das Experiment und prüfen Sie, ob der Zähler weiter steigt. Wenn dies nicht der Fall ist, bedeutet dies, dass Sie keinen verwalteten Speicher verlieren.

    
Senthil Kumar 22.06.2009 19:14
quelle

Tags und Links