Salvar um FixedDocument em um arquivo XPS causa vazamento de memória
Criei um .NET Windows Service que executa determinadas ações e gera relatórios. Esses relatórios são documentos XPS que eu salvo em um determinado diretóri
Familiarizando-se com o WPF, a maneira que escolhi para criar os relatórios é instanciar umSystem.Windows.Documents.FixedDocument
, adicionandoFixedPage
bjetos com conteúdo conforme necessári
Meu problema é que o uso da memória do Serviço aumenta e aumenta ao longo do tempo à medida que é executad
No começo, analisei meu código rigorosamente, assegurando que todos os objetos descartáveis fossem descartados etc. e outros candidatos óbvios a vazamentos de memória, mas ainda tinha o problema. Em seguida, usei o CLR Profiler para examinar detalhadamente o uso de memória do Serviço.
Descobri que, como o serviço gera essesFixedDocument
relata e os salva como arquivos XPS, todos os vários elementos da interface do usuário associados aFixedDocument
objetos Dispatcher
, FixedPage
, UIElementCollection
, Visual
etc) estão na memóri
Isso parece não acontecer quando eu faço a mesma coisa nos meus aplicativos WPF e, portanto, meu palpite é que ele tem algo a ver com o modelo do Dispatcher de interface do usuário do WPF sendo usado fora de um aplicativo WP
Como posso "descartar" meuFixedDocument
bjetos ao usá-los em um serviço como este (ou fora de um aplicativo WPF em geral
======== EDIT =========
OK, eu descobri que meu vazamento de memória não está especificamente relacionado à criação / preenchimento de um FixedDocument. Se fizer isso, mas nunca o salve no disco como um XPS, o vazamento de memória não acontece. Portanto, meu problema deve estar relacionado ao salvamento como arquivo XPS.
Aqui está o meu código:
var paginator = myFixedDocument.DocumentPaginator;
var xpsDocument = new XpsDocument(filePath, FileAccess.Write);
var documentWriter = XpsDocument.CreateXpsDocumentWriter(xpsDocument);
documentWriter.Write(paginator);
xpsDocument.Close();
O que eu tentei:
Coleta de lixo manualCallingUpdateLayout()
em cada página demyFixedDocument
antes de obter o paginador (como sugerido na resposta abaixo) - eu também tentei passarmyFixedDocument
diretamente paraWrite()
ou seja, não o paginador Colocando essas linhas de código em seu próprio encadeamento e desligando manualmente os DispatchersAinda sem sorte.
========== SOLUÇÃO ==========
Isolando o código acima em seu próprio AppDomain usando o método geral mostrado no exemplo emhttp: //msdn.microsoft.com/en-us/library/system.appdomain.asp, o vazamento de memória não afeta mais o meu serviço (eu digo "não afeta mais" porque ainda acontece, mas quando o AppDomain é descarregado, todos os recursos vazados são descarregados
Eu ainda gostaria de ver uma solução real.
(Em uma nota relacionada, para os interessados, o uso de um AppDomain separado causou um vazamento de memória no componente PDFSharp que eu estava usando para transformar determinados arquivos XPS em arquivos PDF. Acontece que o PDFSharp usa um cache global de fontes que, em circunstâncias normais, não crescer significativamente. Mas o cache foi crescendo após o uso desses AppDomains. Editei o código-fonte PDFSharp para permitir a limpeza manual do FontDescriptorStock e FontDataStock, resolvendo o problema.)
========== SOLUÇÃO ==========
Veja minha resposta abaixo para a solução fina