2012-11-13 7 views
8

Ho lavorato a un'app WP7, è un'app per galleria di immagini, con zoom e gesti rapidi.Impossibile trovare la perdita di memoria

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

Ma ci siamo resi conto che l'app consuma molta memoria. Ho pensato che fosse dovuto a immagini e trovato this 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 funzionalità 2 di base per la navigazione e il controllo dell'immagine per le immagini, solo per accertarmi che non fossero i miei codici gestuali il problema.

Questo è il codice XAML

<Grid x:Name="LayoutRoot" Background="Transparent"> 
    <Grid.RowDefinitions> 
     <RowDefinition Height="*" /> 
     <RowDefinition Height="Auto" /> 
    </Grid.RowDefinitions> 
    <Image Grid.Row="0" x:Name="ImageHolder" Height="Auto" Width="Auto" Stretch="Uniform" Tap="image_Tap" /> 
    <TextBlock x:Name="MemUsage" /> 
    <StackPanel Grid.Row="1" Orientation="Horizontal"> 
     <Button x:Name="PrevButton" Content="Prev" Width="240" Click="btnPrev_Click"/> 
     <Button x:Name="NextButton" Content="Next" Width="240" Click="btnNext_Click"/> 
    </StackPanel> 
</Grid> 

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 ancora perdita di memoria è lì e non riesco a pin punto. Sto avendo difficoltà a trovarlo. Il profiler della memoria mostra che ho molte istanze di una stringa e non riesco a interpretarlo.

alcuni punti:

  • Ho immagini di una cartella "000" e il nome di "immagine ###". Attualmente ho immagini con nomi di file da "image001" a "image042"
  • L'app di test ha un footprint di memoria di 6 MB non appena mostra la prima pagina completamente con l'immagine, e dopo il primo cambio di pagina sale quasi a 18-20 MB
  • successivamente risultato cambiamento pagina in aumento graduale della memoria e crash poi eventuale, se il numero di immagini permette, altrimenti dopo in bicicletta attraverso tutto il consumo di memoria immagini è costante
  • sto usando file .jpg con ca. dimensione 1280 x 2000, per il test non sto ridimensionando le immagini.

Heap Summary -> New Allocations

+0

Si sta generando un thread aggiuntivo per ogni immagine visualizzata per renderlo? Hai oggetti Thread 1918 in giro. Non sembra sano. Scopri come creare i thread e terminarli correttamente in modo che le risorse associate a cui fa riferimento il metodo thread possano essere rilasciate. –

+0

@Alois, non sono un professionista, solo uno sviluppatore hobbista. Non ho idea di dove sto creando accidentalmente discussioni. Non sto creando alcun thread in modo esplicito. Non lo so nemmeno, è davvero un problema. Quello che posso dire che quello che stai vedendo è l'intero codice della mia app di esempio. Quindi, se potessi ricrearlo, dargli un'occhiata. Sarebbe utile. –

risposta

5

Ho lo stesso tipo di applicazione, con i precedenti pulsanti successivi/immagine. 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.

In ogni caso, qui è l'hack:

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

Si può chiamare, per esempio nel 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(); 
} 

Kinda vergogna di usare quella, ma almeno sembra funzionare.

+0

Ti stavo cercando. Ti vedo come uno dei membri più attivi nell'area WP7. SO potrebbe essere un dispositivo PM. Comunque la soluzione che hai proposto sembra essere giusta. Io stesso avevo pensato di farlo. Lo segnerò come risposta, ma non lo confermerò. Vedi la mia risposta per quello. Ma grazie per l'aiuto. –

1

Ho cercato il tuo esempio di codice, ma in Windows Phone 8 ambiente e non riuscivo 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?

(btw, visivamente non vedo perdite di memoria nel codice).

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

+0

"visivamente non vedo alcuna perdita di memoria nel codice dietro"; questo è ciò che mi confonde. Proverò l'associazione dei dati, grazie per la risposta. –

1

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 nell'isolamento isolato dell'applicazione.

A cosa sto 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 memorizzati 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 rileva che le immagini non provengono da una memoria 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. enter image description here