【问题标题】:Saving a FixedDocument to an XPS file causes memory leak将 FixedDocument 保存到 XPS 文件会导致内存泄漏
【发布时间】:2012-02-03 06:35:23
【问题描述】:

我创建了一个 .NET Windows 服务,它执行某些操作并生成报告。这些报告是我保存在某个目录中的 XPS 文档。

由于熟悉 WPF,我选择创建报告的方式是实例化 System.Windows.Documents.FixedDocument,并根据需要添加带有内容的 FixedPage 对象。

我的问题是服务内存使用量随着时间的推移不断增加。

起初,我严格检查了我的代码,确保所有一次性对象都被释放,等等,以及其他明显的内存泄漏候选,但仍然存在问题。然后我使用 CLR Profiler 详细查看了 Service 的内存使用情况。

我发现当服务生成这些 FixedDocument 报告并将它们保存为 XPS 文件时,所有与 FixedDocument 对象相关的各种 UI 元素(DispatcherFixedPageUIElementCollectionVisual等) 留在记忆中。

当我在 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();

我尝试过的:

  • 手动垃圾回收
  • 在获得分页器之前在myFixedDocument 的每一页上调用UpdateLayout()(如下面的答案中所建议的) - 我也尝试将myFixedDocument 直接传递给Write(),即不是分页器
  • 将这些代码行放在自己的线程中并手动关闭调度程序

还是没有运气。

========== 解决方法===========

通过使用http://msdn.microsoft.com/en-us/library/system.appdomain.aspx 示例中所示的通用方法将上述代码隔离到自己的 AppDomain 中,内存泄漏不再影响我的服务(我说“不再影响”,因为它仍然会发生,但是当 AppDomain被卸载,所有泄漏的资源都被卸载)。

我仍然渴望看到真正的解决方案。

(在相关说明中,对于那些感兴趣的人,使用单独的 AppDomain 会导致我用来将某些 XPS 文件转换为 PDF 文件的 PDFSharp 组件中的内存泄漏。原来 PDFSharp 使用全局字体缓存,在正常情况下不会'没有显着增长。但是使用这些AppDomains后缓存越来越大。我编辑了PDFSharp源代码,使我能够手动清除FontDescriptorStock和FontDataStock,解决了这个问题。)

==========解决方案===========

请参阅下面的答案以获得最终解决方案。

【问题讨论】:

  • 检查几乎完全相同的重复:stackoverflow.com/questions/5883779/…
  • 对该问题的未经证实的答案是强制 GC 垃圾收集。虽然我不认为这是一个可以接受的解决方案,但我还是尝试了它,但它对我不起作用。还是谢谢。

标签: wpf memory-leaks dispatcher xpsdocument fixeddocument


【解决方案1】:

我最终找到了答案,分两部分。

首先,在将我的 XPS 文档保存到磁盘并关闭/处理 XpsDocument 之后,我运行以下代码行:

Dispatcher.CurrentDispatcher.Invoke(DispatcherPriority.SystemIdle, new DispatcherOperationCallback(delegate { return null; }), null);

这消除了所有在内存中徘徊的Dispatcher 对象。

虽然上面解决了大部分内存问题,但我注意到仍然有 FixedPage 对象以及其他 UI 对象仍在内存中。手动清除我的 FixedDcoument 似乎可以摆脱它们:

foreach (var fixedPage in FixedDocument.Pages.Select(pageContent => pageContent.Child)) {
   fixedPage.Children.Clear();
}

【讨论】:

  • 谢谢,我正要走“AppDomain”路线,但这似乎很好用!我还验证了它确实似乎是 Microsoft 的问题,FixedDocument 与静态属性“SerializableObjectContext”相关联并且从未从中释放。这样就解释了内存泄漏。
  • 你拯救了我的一天!谢谢!
【解决方案2】:

来自this,看来您必须至少调用一次 .UpdateLayout() 以避免内存泄漏

【讨论】:

  • 这个问题与打开 XPS 文档有关,而不是在内存中创建 FixedDocument 对象。无论如何,我尝试了它提到的关于 UpdateLayout() 调用的各种解决方案,唉,没有一个对我有用:-(
  • 你能把产生问题的部分代码贴出来吗?我可以帮忙找出它的来源。
  • 我用更多信息和一些示例代码编辑了我的答案 - 如果你认为你看到了一个很棒的解决方案。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-09-02
  • 2016-12-07
  • 2023-03-14
  • 2021-03-04
  • 1970-01-01
  • 2021-03-23
  • 2021-09-25
相关资源
最近更新 更多