Я создал службу .NET Windows, которая выполняет определенные действия и создает отчеты.Эти отчеты являются документами 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()
, т.е. не в paginator - Поместить эти строки кода в их собственный поток и вручную отключить диспетчеры
Все еще не повезло.
========== ВРЕМЕННОЕ РЕШЕНИЕ==========
Путем выделения вышеуказанного кода в свой собственный домен приложений с использованием общего метода, показанного в примере в http://msdn.microsoft.com/en-us/library/system.appdomain.aspx,, утечка памяти больше не влияет на мой сервис (яскажем «больше не влияет», потому что это все еще происходит, но когда домен приложения выгружен, все просочившиеся ресурсы выгружаются вместе с ним).
Я все равно хотел бы увидеть реальное решение.
(Для связанного примечания, для заинтересованных, использование отдельного AppDomain вызвало утечку памяти вКомпонент PDFSharp, который я использовал для преобразования некоторых файлов XPS в файлы PDF.Оказывается, PDFSharp использует глобальный кэш шрифтов, который в нормальных условиях существенно не растет.Но кэш рос и рос после использования этих доменов приложений.Я отредактировал исходный код PDFSharp, чтобы я мог вручную очистить FontDescriptorStock и FontDataStock, решив проблему.)
========== РЕШЕНИЕ ==========
См. Мой ответ ниже для окончательного решения.