2012-01-05 11 views
8

He creado un servicio Windows .NET que realiza ciertas acciones y genera informes. Estos informes son documentos XPS que guardo en un directorio determinado.Guardar un FixedDocument en un archivo XPS provoca una pérdida de memoria

Al estar familiarizado con WPF, la forma en que he elegido crear los informes es instanciar un System.Windows.Documents.FixedDocument, agregando FixedPage objetos con el contenido requerido.

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 estaban dispuestos, etc., y otros candidatos obvios a la pérdida de memoria, pero aún así tenía el problema. Luego utilicé CLR Profiler para ver el uso de la memoria del Servicio en detalle.

He encontrado que a medida que el servicio genera estos informes FixedDocument, y las guarda como archivos XPS, todos los diversos elementos de interfaz de usuario asociados con objetos (FixedDocumentDispatcher, FixedPage, UIElementCollection, Visual, etc) están alojados en la memoria.

Esto no parece suceder cuando hago lo mismo en mis aplicaciones WPF, por lo que mi corazonada es que tiene algo que ver con el modelo WPF UI Dispatcher que se utiliza fuera de una aplicación WPF.

¿Cómo puedo "desechar" mis objetos FixedDocument cuando los utilizo en un servicio como este (o fuera de una aplicación WPF en general)?

======== ========= EDITAR

OK, he encontrado que mi pérdida de memoria no es específicamente que ver con la creación/llenar una FixedDocument. 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 tiene que ver 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 intentado:

  • recolección manual de basura
  • Calling UpdateLayout() en cada página del myFixedDocument antes de conseguir que del paginador (como se sugiere en la respuesta a continuación) - También he intentado pasar myFixedDocument directamente en Write() es decir, no el paginador
  • Poner esas líneas de código en su propio hilo y cerrar manualmente Despachadores

Todavía no hubo suerte.

Solución ========== ==========

Al aislar el código anterior en su propio dominio de aplicación usando el método general que se muestra en el ejemplo en http://msdn.microsoft.com/en-us/library/system.appdomain.aspx, la la pérdida de memoria ya no afecta mi servicio (digo "ya no me afecta" porque todavía sucede, pero cuando el AppDomain está descargado, todos los recursos filtrados se descargan con él).

Todavía estaría ansioso por ver una solución real.

(En una nota relacionada, para los interesados, el uso de un dominio de aplicación separado causó una pérdida de memoria en el componente PDFSharp que estaba utilizando para convertir ciertos archivos XPS en archivos PDF. Resulta que PDFSharp utiliza un caché de fuente global que en circunstancias normales no crece significativamente. Pero la caché estaba creciendo y creciendo después de usar estos dominios de aplicación. edité el código fuente PDFsharp que me permita borrar manualmente el FontDescriptorStock y FontDataStock, la solución del problema.)

===== ===== SOLUCIÓN ==========

Consulte mi respuesta a continuación para la solución final.

+0

cheque casi exacta duplicado: http://stackoverflow.com/questions/5883779/how-to-dispose-a-fixeddocument – Nat

+0

La respuesta no confirmada a ese La pregunta es forzar la recolección de basura GC. Si bien no considero que esto sea una solución aceptable, lo intenté de todos modos y no funcionó para mí. Gracias de cualquier manera. – Ross

Respuesta

15

final encontré una respuesta, que es de dos partes.

En primer lugar, después de guardar mi documento XPS en el disco y cierre/disponer el XpsDocument, que ejecute la siguiente línea de código:

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

Esto se deshace de todos los objetos que cuelgan alrededor Dispatcher en la memoria.

Mientras que lo anterior soluciona la mayoría de los problemas de memoria, noté que todavía había objetos FixedPage junto con otros objetos de UI todavía en la memoria. limpiar manualmente mi FixedDcoument parece deshacerse de ellos:

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

muchas gracias, gran cosa! –

+1

gracias, estaba a punto de ir por el " AppDomain "ruta, pero parece funcionar muy bien! También verifiqué que parece ser un problema de Microsoft donde FixedDocument está asociado con la propiedad estática" SerializableObjectContext "y nunca se liberó de él. Eso explica la fuga de memoria –

+0

thnaks hombre, solución para salvar vidas;) – Miran

0

De this, parece que usted tiene que llamar .UpdateLayout() al menos una vez para evitar pérdida de memoria

+0

Esa pregunta tiene que ver con abrir documentos XPS, no crear objetos FixedDocument en la memoria. A pesar de eso, probé las diversas soluciones que menciona con respecto a la llamada de UpdateLayout() y, por desgracia, ninguna me funcionó :-( – Ross

+0

¿Puede publicar parte del código donde produce el problema? Puedo ayudar a encontrar su origen. – Nat

+0

He editado mi respuesta con un poco más de información y algunos ejemplos de código, si crees que ves una solución que sería increíble. – Ross

Cuestiones relacionadas