特定のアクションを実行してレポートを生成する .NET Windows サービスを作成しました。これらのレポートは、特定のディレクトリに保存する XPS ドキュメントです。
WPF に精通しているため、レポートを作成するために選択した方法は、 をインスタンス化し 、必要に応じてコンテンツを含むオブジェクトをSystem.Windows.Documents.FixedDocument
追加することです。FixedPage
私の問題は、サービスのメモリ使用量が、実行中に時間の経過とともにどんどん増えていくということです。
最初に、すべての破棄可能なオブジェクトが破棄されることを確認するなど、コードを厳密に調べましたが、その他の明らかなメモリ リークの候補もありましたが、それでも問題がありました。次に、CLR プロファイラーを使用して、サービスのメモリ使用量を詳細に調べました。
サービスがこれらのレポートを生成し、それらを XPS ファイルとして保存すると、オブジェクト ( 、、、など) にFixedDocument
関連付けられたさまざまな UI 要素がすべてメモリに保持されることがわかりました。FixedDocument
Dispatcher
FixedPage
UIElementCollection
Visual
これは、WPF アプリで同じことを行った場合には発生しないようです。そのため、WPF アプリの外部で使用されている WPF UI ディスパッチャー モデルと関係があると思います。
FixedDocument
このようなサービス (または一般的に WPF アプリの外部) でオブジェクトを使用する場合、オブジェクトを「破棄」するにはどうすればよいですか?
========編集=========
OK、私のメモリ リークは、FixedDocument の作成/入力に特に関係していないことがわかりました。そうしても、実際には XPS としてディスクに保存しないと、メモリ リークは発生しません。したがって、私の問題は、XPSファイルとして保存することに関係しているに違いありません。
これが私のコードです:
var paginator = myFixedDocument.DocumentPaginator;
var xpsDocument = new XpsDocument(filePath, FileAccess.Write);
var documentWriter = XpsDocument.CreateXpsDocumentWriter(xpsDocument);
documentWriter.Write(paginator);
xpsDocument.Close();
私が試したこと:
- 手動ガベージ コレクション
UpdateLayout()
ページネーターを取得する前に各ページを呼び出しますmyFixedDocument
(以下の回答で示唆されているように)-ページネーターで はなく、myFixedDocument
直接渡そうとしましたWrite()
- これらのコード行を独自のスレッドに配置し、ディスパッチャーを手動でシャットダウンする
まだ運がありません。
========== 回避策 ==========
http://msdn.microsoft.com/en-us/library/system.appdomain.aspxの例に示されている一般的な方法を使用して上記のコードを独自の AppDomain に分離することにより、メモリ リークはサービスに影響しなくなりました (私はまだ発生しているため、「もう影響はありません」と言いますが、AppDomain がアンロードされると、リークされたすべてのリソースがアンロードされます)。
私はまだ本当の解決策を見たいと思っています。
(関連する注意事項として、別の AppDomain を使用すると、特定の XPS ファイルを PDF ファイルに変換するために使用していた PDFSharp コンポーネントでメモリ リークが発生しました。PDFSharp は、通常の状況では拡大しないグローバル フォント キャッシュを使用することが判明しました。しかし、これらの AppDomains を使用した後、キャッシュはどんどん大きくなっていきました. PDFSharp のソース コードを編集して、FontDescriptorStock と FontDataStock を手動でクリアできるようにし、問題を解決しました.)
========== ソリューション ==========
最終的な解決策については、以下の私の回答を参照してください。