Сохранение FixedDocument в файл XPS приводит к утечке памяти
Я создал .NET Windows Service, который выполняет определенные действия и генерирует отчеты. Эти отчеты являются документами XPS, которые я сохраняю в определенном каталоге.
Будучи знакомым с WPF, я решил создать отчеты для создания экземпляраSystem.Windows.Documents.FixedDocument
, добавивFixedPage
объекты с содержанием по мере необходимости.
Моя проблема заключается в том, что использование служебной памяти с течением времени увеличивается и увеличивается.
Сначала я тщательно просмотрел свой код, убедившись, что все одноразовые объекты были уничтожены и т. Д., И других очевидных кандидатов на утечку памяти, но все еще имел проблему. Затем я использовал CLR Profiler, чтобы подробно рассмотреть использование сервиса Сервисом.
Я обнаружил, что, поскольку сервис генерирует этиFixedDocument
отчеты и сохраняет их в виде файлов XPS, все различные элементы пользовательского интерфейса, связанные сFixedDocument
объекты (Dispatcher
, FixedPage
, UIElementCollection
, Visual
и т. д.) остаются в памяти.
Похоже, этого не происходит, когда я делаю то же самое в своих приложениях WPF, и поэтому я догадываюсь, что это как-то связано с моделью диспетчера пользовательского интерфейса WPF, используемой вне приложения WPF.
Как я могу "распоряжаться" своимFixedDocument
объекты при использовании их в таком сервисе (или вообще вне приложения WPF)?
======== РЕДАКТИРОВАТЬ =========
Хорошо, я обнаружил, что утечка памяти не связана с созданием / заполнением 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
до того, как получить его paginator (как предложено в ответе ниже) - я также пытался пройтиmyFixedDocument
прямо вWrite()
то есть не пагинаторПоместить эти строки кода в их собственный поток и вручную отключить диспетчерыВсе еще не повезло.
========== Временное решение ==========
Выделив приведенный выше код в свой собственный домен приложения, используя общий метод, показанный в примере наhttp://msdn.microsoft.com/en-us/library/system.appdomain.aspxутечка памяти больше не влияет на мой сервис (я говорю «больше не влияет», потому что это все еще происходит, но когда AppDomain выгружен, все утечки ресурсов выгружаются с ним).
Я все еще хотел бы увидеть реальное решение.
(Для связанного примечания, для заинтересованных, использование отдельного AppDomain вызвало утечку памяти в компоненте PDFSharp, который я использовал, чтобы превратить определенные файлы XPS в файлы PDF. Оказывается, PDFSharp использует глобальный кэш шрифтов, который в нормальных условиях не растет значительно. Но кэш рос и рос после использования этих доменов приложений. Я отредактировал исходный код PDFSharp, чтобы я мог вручную очистить FontDescriptorStock и FontDataStock, решая проблему.)
========== РЕШЕНИЕ ==========
Смотрите мой ответ ниже для окончательного решения.