Imansible trovare la perdita di memoria

Ho lavorato a un’app WP7, la sua app per immagini, con implementati zoom e gesti rapidi.

A scopo di test, ho compilato l’app con immagini offline (i loro nomi di file sono numerati) impostate su Content e le ho consultate tramite una stringa codificata (che verrà sostituita in seguito).

Ma ho capito che l’app consuma molta memoria. Pensavo fosse dovuto alle immagini e ho trovato questo blog ; le immagini erano sempre in cache. Ho usato il codice dal blog per rettificare questo. La memoria non viene ancora rilasciata, sebbene la velocità di consumo sia diminuita.

Per il tentativo finale, ho creato un’altra app di test con il pulsante di base della funzionalità 2 per la navigazione e il controllo dell’immagine per le immagini, solo per accertarmi che non fossero i miei codici gestuali a rappresentare il problema.

Questo è l’xaml

        

Questo è il file .cs

  const int PAGE_COUNT = 42; int pageNum = 0; public MainPage() { InitializeComponent(); RefreshImage(); } private void btnPrev_Click(object sender, RoutedEventArgs e) { pageNum = (PAGE_COUNT + pageNum - 1) % PAGE_COUNT; // cycle to prev image RefreshImage(); } private void btnNext_Click(object sender, RoutedEventArgs e) { pageNum = (PAGE_COUNT + pageNum + 1) % PAGE_COUNT; // cycle to next image RefreshImage(); } private void image_Tap(object sender, GestureEventArgs e) { RefreshTextData(); } private void RefreshImage() { BitmapImage image = ImageHolder.Source as BitmapImage; ImageHolder.Source = null; if (image != null) { image.UriSource = null; image = null; } ImageHolder.Source = new BitmapImage(new Uri("000\\image" + (pageNum + 1).ToString("D3") + ".jpg", UriKind.Relative)); RefreshTextData(); } private void RefreshTextData() { MemUsage.Text = "Device Total Memory = " + (long)DeviceExtendedProperties.GetValue("DeviceTotalMemory") / (1024 * 1024) + "\nCurrent Memory Usage = " + (long)DeviceExtendedProperties.GetValue("ApplicationCurrentMemoryUsage") / (1024 * 1024) + "\nPeak Memory Usage = " + (long)DeviceExtendedProperties.GetValue("ApplicationPeakMemoryUsage") / (1024 * 1024); } 

Ma c’è ancora perdita di memoria e non riesco a capirlo. Sto avendo difficoltà a trovarlo. Il profiler della memoria mostra che ho molte istanze di una stringa e non riesco a interpretarlo.

Pochi punti

  • Ho immagini in una cartella “000” e denominate “immagine ###”. Al momento ho immagini con nomi di file da “image001” a “image042”
  • L’app di prova ha un ingombro di memoria di 6 MB non appena mostra la prima pagina completamente con l’immagine, e dopo la prima pagina cambia fino a quasi 18-20 MB
  • Le modifiche successive alla pagina comportano un aumento graduale della memoria e quindi un eventuale arresto anomalo se il numero di immagini lo consente, altrimenti dopo aver attraversato tutte le immagini il consumo di memoria è costante
  • Sto usando i file .jpg con dimensioni approssimative di 1280 x 2000, per i test non sto ridimensionando le immagini.

Nuove allocazioni”>

Ho lo stesso tipo di app, con i pulsanti immagine successiva / precedente. E ho avuto esattamente la stessa perdita di memoria, che mi ha fatto impazzire.

Non sono ancora riuscito a trovare la causa principale, ma sono riuscito a bypassarlo con un brutto attacco. Quando si visualizza l’immagine successiva, impongo alla vecchia sorgente di immagini di caricare un’immagine non valida, liberando così la memoria. Non capisco perché rimuovere tutti i riferimenti e chiamare il garbage collector non è sufficiente, ci deve essere un altro riferimento mantenuto internamente da qualche parte.

Comunque, ecco l’hack:

 private void DisposeImage(BitmapImage image) { if (image != null) { try { using (var ms = new MemoryStream(new byte[] { 0x0 })) { image.SetSource(ms); } } catch (Exception) { } } } 

Puoi chiamarlo ad esempio nel tuo metodo RefreshImage :

 private void RefreshImage() { BitmapImage image = ImageHolder.Source as BitmapImage; ImageHolder.Source = null; DisposeImage(image); ImageHolder.Source = new BitmapImage(new Uri("000\\image" + (pageNum + 1).ToString("D3") + ".jpg", UriKind.Relative)); RefreshTextData(); } 

Un po ‘vergognoso di usarlo, ma almeno sembra funzionare.

Ho provato il tuo esempio di codice, ma in ambiente Windows Phone 8 e non sono riuscito a riprodurre la perdita. L’unica differenza è che ho usato le mie immagini.

L’attuale utilizzo della memoria è rimasto a 13 MB per il mio emulatore WVGA 512 e il picco è rimasto a 14 MB. Ho premuto il “pulsante successivo” circa 20 volte.

Hai anche provato a utilizzare Bindings per ImageHolder invece di impostare manualmente la sorgente?

(A proposito, visivamente non vedo alcuna perdita di memoria nel codice dietro).

(Controlla anche questo articolo http://blogs.windows.com/windows_phone/b/wpdev/archive/2012/02/01/memory-profiling-for-application-performance.aspx )

Dopo molte sessioni di prova e sessioni di debug, ho scoperto che questa memorizzazione nella cache delle immagini non viene eseguita (o non eseguita in modo aggressivo) quando le immagini risiedono in IsolatedStorage dell’app.

Il fatto è che stavo usando le immagini che facevano parte del file xap, incluso come contenuto. L’ho fatto perché volevo solo testare il mio visualizzatore di immagini. Ma questo non sarebbe il caso quando la mia app finirebbe. L’app è stata davvero progettata per archiviare le immagini nell’archiviazione isolata e visualizzarle.

Così ho impostato il codice necessario e voilà, Le immagini ora stanno recuperando i dati inutili, anche se sono ancora stati salvati nella cache. Vedi l’immagine qui sotto (vedi quante volte viene chiamato il Garbage Collector). Questa è una soluzione a una domanda non tanto banale, ecco perché nessun altro ha affrontato un problema di questo tipo.

Credo che quando WP7 Silverlight scopre che le immagini non provengono dall’archiviazione isolata, presuppone che l’immagine provenga da qualche URI remoto e decida di memorizzarla comunque. Ed è qui che entra in gioco il problema del caching delle immagini Silverlight. Come conferma un’altra risposta, ciò non accade nel WP8. inserisci la descrizione dell'immagine qui

Prova questo approccio: Downloader di immagini con pulizia automatica della memoria . È l’esempio avanzato di KooKiZ, che supporta la visualizzazione. Il progetto di esempio è qui: https://simca.codeplex.com/