我创建了一个.NET Windows服务,它执行某些操作并生成报告。这些报告是我保存在某个目录中的XPS文档。
熟悉WPF,我选择创建报告的方式是实例化System.Windows.Documents.FixedDocument
,根据需要添加包含内容的FixedPage
个对象。
我的问题是服务内存使用率随着时间的推移而不断上升和下降。
起初,我严格检查了我的代码,确保所有一次性物品都被丢弃等,以及其他明显的内存泄漏候选者,但仍然存在问题。然后,我使用CLR Profiler详细查看了服务的内存使用情况。
我发现,当服务生成这些FixedDocument
报告并将其保存为XPS文件时,与FixedDocument
个对象关联的所有各种UI元素(Dispatcher
,FixedPage
,UIElementCollection
,Visual
等等留在记忆中。
当我在WPF应用程序中执行相同操作时似乎没有发生这种情况,因此我的预感是它与在WPF应用程序之外使用的WPF UI Dispatcher模型有关。
在这样的服务中(或者在WPF应用程序之外)使用它们时,如何“处置”我的FixedDocument
个对象?
========编辑=========
好的,我发现我的内存泄漏并不是专门用于创建/填充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导致我正在使用的PDFSharp组件中的内存泄漏将某些XPS文件转换为PDF文件。结果PDFSharp使用全局字体缓存,在正常情况下不会使用这些AppDomains后,缓存增长和增长。我编辑了PDFSharp源代码,使我能够手动清除FontDescriptorStock和FontDataStock,解决了这个问题。)
==========解决方案==========
请参阅下面的答案以获得最终解决方案。
答案 0 :(得分:17)
我最终找到了答案,这是两部分。
首先,在将我的XPS文档保存到磁盘并关闭/部署XpsDocument
之后,我运行以下代码行:
Dispatcher.CurrentDispatcher.Invoke(DispatcherPriority.SystemIdle, new DispatcherOperationCallback(delegate { return null; }), null);
这消除了内存中所有的Dispatcher
个对象。
虽然上面排除了大部分内存问题,但我注意到仍有固定页面对象以及其他UI对象仍在内存中。手动清除我的FixedDcoument似乎摆脱了它们:
foreach (var fixedPage in FixedDocument.Pages.Select(pageContent => pageContent.Child)) {
fixedPage.Children.Clear();
}
答案 1 :(得分:0)
从this开始,您似乎必须至少调用一次.UpdateLayout()以避免内存泄漏