Я создал .NET Windows Service, который выполняет определенные действия и генерирует отчеты. Эти отчеты представляют собой документы XPS, которые я сохраняю в определенном каталоге.
Поскольку я знаком с WPF, я выбрал способ создания отчетов - создать экземпляр System.Windows.Documents.FixedDocument
, добавив при необходимости объекты FixedPage
с содержимым.
Моя проблема в том, что использование служебной памяти постоянно увеличивается и увеличивается по мере его работы.
Сначала я тщательно изучил свой код, убедившись, что все одноразовые объекты удалены и т. Д., И другие очевидные кандидаты на утечку памяти, но проблема все еще оставалась. Затем я использовал профилировщик CLR, чтобы подробно изучить использование памяти Службой.
Я обнаружил, что по мере того, как служба генерирует эти отчеты FixedDocument
и сохраняет их в виде файлов XPS, все различные элементы пользовательского интерфейса, связанные с объектами FixedDocument
( Dispatcher
] , FixedPage
, UIElementCollection
, Visual
и т. Д.) Остаются в памяти.
Похоже, этого не происходит, когда я делаю то же самое в своих приложениях WPF, и поэтому я догадываюсь, что это как-то связано с моделью диспетчера пользовательского интерфейса WPF, используемой вне приложения WPF.
Как я могу "избавиться" от моих объектов FixedDocument
при использовании их в такой службе (или вне приложения WPF в целом)?
======== EDIT == =======
Хорошо, я обнаружил, что моя утечка памяти не связана конкретно с созданием / заполнением 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, утечка памяти больше не влияет на мою службу (я говорю «больше не влияет», потому что это все еще происходит, но когда домен приложения выгружается , с ним выгружаются все утекшие ресурсы).
Мне все еще хотелось бы увидеть реальное решение.
(Кстати, для тех, кто заинтересован, использование отдельного домена приложений вызвало утечку памяти в компоненте PDFSharp, который я использовал для преобразования определенных файлов XPS в файлы PDF.Оказывается, PDFSharp использует глобальный кеш шрифтов, который в нормальных условиях существенно не увеличивается. Но после использования этих доменов приложений кеш рос и разрастался. Я отредактировал исходный код PDFSharp, чтобы я мог вручную очистить FontDescriptorStock и FontDataStock, решив проблему.)
========== РЕШЕНИЕ ==========
См. Мой ответ ниже для окончательного решения.