本文介绍了将FixedDocument保存到XPS文件会导致内存泄漏的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I have created a .NET Windows Service which performs certain actions and generates reports. These reports are XPS documents which I save in a certain directory.

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

Being familiar with WPF, the way I have chosen to create the reports is to instantiate a System.Windows.Documents.FixedDocument, adding FixedPage objects with content as required.

我的问题是服务内存使用量随着运行时间的增长而不断增加.

首先,我严格地检查了我的代码,确保处理掉所有可抛弃的对象等,以及其他明显的内存泄漏候选对象,但是仍然存在问题.然后,我使用CLR Profiler来详细查看服务的内存使用情况.

At first, I went through my code rigorously, ensuring all disposable objects were disposed, etc, and other obvious memory leak candidates, but still had the problem. I then used the CLR Profiler to look at the memory usage of the Service in detail.

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

I found that as the service generates these FixedDocument reports, and saves them as XPS files, all the various UI elements associated with FixedDocument objects (Dispatcher, FixedPage, UIElementCollection, Visual, etc) are staying in memory.

当我在WPF应用程序中执行相同的操作时,似乎没有发生这种情况,因此我的直觉是,这与WPF应用程序外部使用的WPF UI Dispatcher模型有关.

This doesn't seem to happen when I do the same thing in my WPF apps, and so my hunch is that it has something to do with the WPF UI Dispatcher model being used outside of a WPF app.

在这样的服务中(或通常在WPF应用程序外部)使用我的FixedDocument对象时,如何放置"我的FixedDocument对象?

How can I "dispose" my FixedDocument objects when using them in a service like this (or outside a WPF app in general)?

=========编辑========

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

好的,我发现我的内存泄漏与创建/填充FixedDocument无关.如果这样做,但实际上从未将其作为XPS保存到磁盘,则不会发生内存泄漏.因此,我的问题必须与另存为XPS文件有关.

OK, I've found that my memory leak is not specifically to do with creating/populating a FixedDocument. If I do so, but don't actually ever save it to disk as a XPS, the memory leak doesn't happen. So, my problem must be to do with the save as XPS file.

这是我的代码:

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()中,即不是分页器
  • 将这些代码行放在自己的线程中,然后手动关闭分派器
  • Manual garbage collection
  • Calling UpdateLayout() on each page of myFixedDocument before getting it's paginator (as suggested in the answer below) - I've also tried passing myFixedDocument directly into Write() i.e. not the paginator
  • Putting those lines of code in their own thread and manually shutting down Dispatchers

还是没有运气.

==========替代方法=========

========== WORKAROUND ==========

使用示例 http://msdn.microsoft.com/en-us/library/system.appdomain.aspx ,内存泄漏不再影响我的服务(我说不再影响",因为它仍然会发生,但是当卸载AppDomain时,所有泄漏的资源都会随之卸载).

By isolating the above code into its own AppDomain using the general method shown in the example at http://msdn.microsoft.com/en-us/library/system.appdomain.aspx, the memory leak no longer affects my service (I say "no longer affects" because it still happens, but when the AppDomain is unloaded, all leaked resources are unloaded with it).

我仍然渴望看到一个真正的解决方案.

I would still be keen to see a real solution.

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

(On a related note, for those interested, using a separate AppDomain caused a memory leak in the PDFSharp component I was using to turn certain XPS files into PDF files. Turns out PDFSharp uses a global font cache that in normal circumstances doesn't grow significantly. But the cache was growing and growing after using these AppDomains. I edited the PDFSharp source code to enable me to manually clear out the FontDescriptorStock and FontDataStock, solving the issue.)

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

========== SOLUTION ==========

有关最终解决方案,请参见下面的答案.

See my answer below for final solution.

推荐答案

我最终找到了答案,分为两个部分.

I eventually found an answer, which is two parts.

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

Firstly, after saving my XPS document to disk and closing/disposing the XpsDocument, I run the following line of code:

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

这消除了所有挂在内存中的Dispatcher对象.

This gets rid of all the Dispatcher objects hanging around in memory.

尽管以上内容解决了大多数内存问题,但我注意到内存中仍然存在FixedPage对象以及其他UI对象.手动清除我的FixedDcoument似乎摆脱了它们:

While the above sorts out most of the memory issues, I noticed there were still FixedPage objects along with other UI objects still in memory. Manually clearing out my FixedDcoument seems to get rid of them:

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

这篇关于将FixedDocument保存到XPS文件会导致内存泄漏的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

08-15 08:32