2012-01-05 9 views
8

Ho creato un servizio Windows .NET che esegue determinate azioni e genera report. Questi rapporti sono documenti XPS che salvo in una determinata directory.Il salvataggio di un documento fisso in un file XPS causa una perdita di memoria

Conoscendo WPF, il modo in cui ho scelto di creare i report è creare un'istanza di System.Windows.Documents.FixedDocument, aggiungendo gli oggetti FixedPage con i contenuti necessari.

Il mio problema è che l'utilizzo della memoria di servizio aumenta e aumenta nel tempo durante l'esecuzione.

In un primo momento, ho esaminato il mio codice rigorosamente, assicurandomi che tutti gli oggetti monouso fossero stati smaltiti, ecc. E altri ovvi candidati alla perdita di memoria, ma avevo ancora il problema. Ho quindi utilizzato il CLR Profiler per esaminare l'utilizzo della memoria del Servizio in dettaglio.

ho scoperto che il servizio genera questi FixedDocument rapporti, e le salva come file XPS, tutti i vari elementi dell'interfaccia utente associati FixedDocument oggetti (Dispatcher, FixedPage, UIElementCollection, Visual, ecc) si alloggia in memoria.

Questo non sembra accadere quando faccio la stessa cosa nelle mie app WPF, e quindi la mia impressione è che abbia qualcosa a che fare con il modello del Dispatcher UI WPF utilizzato al di fuori di un'app WPF.

Come posso "smaltire" i miei oggetti FixedDocument quando li uso in un servizio come questo (o al di fuori di un'applicazione WPF in generale)?

======== EDIT =========

OK, ho trovato che la mia perdita di memoria non è specificamente a che fare con la creazione/compilazione di un FixedDocument. Se lo faccio, ma in realtà non lo salvi su disco come XPS, la perdita di memoria non si verifica. Quindi, il mio problema deve essere legato al salvataggio come file XPS.

Ecco il mio codice:

var paginator = myFixedDocument.DocumentPaginator; 
var xpsDocument = new XpsDocument(filePath, FileAccess.Write); 
var documentWriter = XpsDocument.CreateXpsDocumentWriter(xpsDocument);       
documentWriter.Write(paginator); 
xpsDocument.Close(); 

Quello che ho provato:

  • garbage collection Manuale
  • Calling UpdateLayout() su ogni pagina del myFixedDocument prima di ottenerlo di paginator (come suggerito nella risposta di seguito) - Ho anche provato a passare myFixedDocument direttamente in Write() ovvero non l'impaginatore
  • Inserimento di quelle righe di codice nella propria discussione e chiusura manuale Dispatcher

Ancora senza fortuna.

========== SOLUZIONE ==========

Isolando il codice sopra in proprio AppDomain utilizzando il metodo generale illustrato nell'esempio in http://msdn.microsoft.com/en-us/library/system.appdomain.aspx, la la perdita di memoria non influisce più sul mio servizio (dico "non influisce più" perché succede ancora, ma quando l'AppDomain viene scaricato, tutte le risorse trapelate vengono scaricate con esso).

Sarei ancora curioso di vedere una soluzione reale.

(Su una nota correlata, per gli interessati, l'utilizzo di un AppDomain separato ha provocato una perdita di memoria nel componente PDFSharp che stavo usando per trasformare determinati file XPS in file PDF. Si scopre che PDFSharp utilizza una cache di carattere globale che in circostanze normali non cresce in modo significativo. Ma la cache è stata in crescita e in crescita dopo l'utilizzo di questi AppDomain. ho modificato il codice sorgente PDFsharp mi consentano di cancellare manualmente la FontDescriptorStock e FontDataStock, risolvendo il problema.)

===== ===== SOLUZIONE ==========

Vedere la mia risposta qui sotto per la soluzione finale.

+0

controllo quasi esatto duplicato: http://stackoverflow.com/questions/5883779/how-to-dispose-a-fixeddocument – Nat

+0

La risposta non confermato a quella la domanda è di forzare la garbage collection di GC. Anche se non ritengo questa una soluzione accettabile, l'ho provato comunque e non ha funzionato per me. Grazie comunque. – Ross

risposta

15

alla fine ho trovato una risposta, che è di due parti.

In primo luogo, dopo aver salvato il mio documento XPS su disco e la chiusura/smaltimento del XpsDocument, ho eseguito il seguente riga di codice:

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

Questo si sbarazza di tutti gli oggetti in giro Dispatcher in memoria.

Mentre sopra elabora la maggior parte dei problemi di memoria, ho notato che c'erano ancora oggetti FixedPage insieme ad altri oggetti UI ancora in memoria. compensazione manualmente il mio FixedDcoument sembra sbarazzarsi di loro:

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

grazie un sacco per questo, roba fantastica! –

+1

grazie amico, stavo per scendere il " AppDomain "route, ma sembra funzionare bene! Ho anche verificato che sembra essere un problema di Microsoft in cui FixedDocument è associato alla proprietà statica" SerializableObjectContext "e non è mai stato rilasciato da esso.Questo tipo di spiegazione della perdita di memoria –

+0

thnaks uomo, soluzione salvavita;) – Miran

0

Da this, sembra che dovete chiamare .UpdateLayout() almeno una volta al fine di evitare perdita di memoria

+0

Questa domanda ha a che fare con l'apertura di documenti XPS, non con la creazione di oggetti FixedDocument in memoria. Indipendentemente da ciò, ho provato le varie soluzioni menzionate per quanto riguarda la chiamata di UpdateLayout(), e ahimè, nessuno ha funzionato per me :-( – Ross

+0

Puoi postare parte del codice dove produce il problema.Posso aiutarti a trovare da dove viene. – Nat

+0

Ho modificato la mia risposta con un po 'più di informazioni e qualche codice di esempio - se pensi di vedere una soluzione che sarebbe fantastica – Ross