Guardar un documento fijo en un archivo XPS provoca una pérdida de memoria
He creado un servicio de Windows .NET que realiza ciertas acciones y genera informes. Estos informes son documentos XPS que guardo en un directorio determinado.
l estar familiarizado con WPF, la forma en que elegí crear los informes es crear una instancia deSystem.Windows.Documents.FixedDocument
, agregandoFixedPage
objetos con contenido según sea necesario.
Mi problema es que el uso de la memoria del Servicio aumenta y aumenta con el tiempo a medida que se ejecuta.
Al principio, revisé mi código rigurosamente, asegurándome de que todos los objetos desechables fueran eliminados, etc., y otros candidatos obvios de pérdida de memoria, pero aún tenía el problema. Luego usé CLR Profiler t, o mire el uso de memoria del Servicio en detalle.
Encontré que a medida que el servicio genera estasFixedDocument
informa y los guarda como archivos XPS, todos los diversos elementos de la interfaz de usuario asociados conFixedDocument
objetos Dispatcher
, FixedPage
, UIElementCollection
, Visual
, etc.) permanecen en la memoria.
Esto no parece suceder cuando hago lo mismo en mis aplicaciones WPF, por lo que mi presentimiento es que tiene algo que ver con el modelo WPF UI Dispatcher que se usa fuera de una aplicación WPF.
¿Cómo puedo "disponer" de miFixedDocument
objetos al usarlos en un servicio como este (o fuera de una aplicación WPF en general)?
======== EDITAR =========
OK, descubrí que mi pérdida de memoria no tiene que ver específicamente con crear / llenar un documento fijo. Si lo hago, pero en realidad nunca lo guardo en el disco como un XPS, la pérdida de memoria no ocurre. Entonces, mi problema debe estar relacionado con guardar como archivo XPS.
Aquí está mi código:
var paginator = myFixedDocument.DocumentPaginator;
var xpsDocument = new XpsDocument(filePath, FileAccess.Write);
var documentWriter = XpsDocument.CreateXpsDocumentWriter(xpsDocument);
documentWriter.Write(paginator);
xpsDocument.Close();
Lo que he probado:
Recolección manual de basuraCallingUpdateLayout()
en cada página demyFixedDocument
antes de obtener su paginador (como se sugiere en la respuesta a continuación) - También he intentado pasarmyFixedDocument
directamente enWrite()
es decir, no el paginadorPoner esas líneas de código en su propio hilo y apagar manualmente DispatchersTodavía no hay suerte.
========== SOLUCIÓN ==========
Al aislar el código anterior en su propio AppDomain utilizando el método general que se muestra en el ejemplo enhttp: //msdn.microsoft.com/en-us/library/system.appdomain.asp, la pérdida de memoria ya no afecta mi servicio (digo "ya no afecta" porque todavía ocurre, pero cuando el dominio de aplicación se descarga, todos los recursos filtrados se descargan con él).
Todavía me gustaría ver una solución real.
(En una nota relacionada, para aquellos interesados, el uso de un dominio de aplicación separado causó una pérdida de memoria en el componente PDFSharp que estaba usando para convertir ciertos archivos XPS en archivos PDF. Resulta que PDFSharp usa un caché de fuentes global que en circunstancias normales no creció significativamente. Pero el caché estaba creciendo y creciendo después de usar estos AppDomains. Edité el código fuente PDFSharp para permitirme limpiar manualmente FontDescriptorStock y FontDataStock, resolviendo el problema.)
========== SOLUCIÓN ==========
Vea mi respuesta a continuación para la solución final.