2013-08-08 8 views
9

Sto testando un'app WP8 ​​e il suo visualizzatore di immagini per mostrare molte immagini, ho scoperto che il consumo di memoria delle app sta aumentando e voglio scoprire come risolverlo.Consumo di memoria di BitmapImmagine/Controllo immagine in Windows Phone 8

Ho letto alcuni articoli dal web, tuttavia le soluzioni fornite da tali articoli non funzionano sulla mia app, si prega di leggere la cronologia qui sotto.

Innanzitutto, ho trovato l'articolo "Image Tips for Windows Phone 7" e scaricato il suo esempio per eseguire il test della cache delle immagini, funziona con 1 immagine.

E poi a scopo di test, io faccio questo app compilato con 15 immagini non in linea all'interno della app, e impostata come "Contenuto", si prega di scaricare test di app dalla here.

miei passi di prova sono:

(1) Launch app 
(2) Go to Image Caching page 
(3) Enable checkbox "Avoid Image Caching" 
(4) Continuously tapping button Show/Clear 
(5) Keep watching the memory status textblock at the bottom 

quando sto testando la mia app, la memoria sta sollevando, come 16.02MB => Show (19.32MB) => Cancella (16.15MB) => Mostra (20.18MB) => Cancella (17.03MB) ... ecc. E la memoria non verrà liberata anche lasciando la pagina di memorizzazione nella cache e tornando alla pagina di memorizzazione nella cache. Sembra che la soluzione dell'articolo "Image Tips for Windows Phone 7" funzioni solo per 1 immagine.

Ecco l'xaml e il code-behind della soluzione di "Image Tips for Windows Phone 7".

[Caching.xaml]

 <Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0"> 
      <StackPanel Orientation="Horizontal" VerticalAlignment="Top"> 
       <ToggleButton Content="Show" Width="150" Checked="ShowImageClicked" Unchecked="ClearImageClicked"/> 
       <CheckBox x:Name="cbAvoidCache" Content="Avoid Image Caching"/> 
      </StackPanel> 
      <Image x:Name="img" Grid.Row="2" Width="256" Height="192"/> 
      <TextBlock x:Name="tbMemory" Grid.Row="2" Text="Memory: " VerticalAlignment="Bottom" Style="{StaticResource PhoneTextLargeStyle}"/> 
     </Grid> 

[Caching.xaml.cs]

public partial class Caching : PhoneApplicationPage 
{ 
    public Caching() 
    { 
     InitializeComponent(); 

     DispatcherTimer timer = new DispatcherTimer(); 
     timer.Interval = TimeSpan.FromMilliseconds(500); 
     timer.Start(); 
     timer.Tick += delegate 
     { 
      GC.Collect(); 
      tbMemory.Text = string.Format("Memory: {0} bytes", DeviceExtendedProperties.GetValue("ApplicationCurrentMemoryUsage")); 
     }; 
    } 

    private int nIndex = 1; 
    BitmapImage bitmapImageFromUri = new BitmapImage(); 
    private void ShowImageClicked(object sender, RoutedEventArgs e) 
    { 
     string strImage = string.Format("../ImagesAsContent/{0:D2}.jpg", nIndex); 
     bitmapImageFromUri.UriSource = new Uri(strImage, UriKind.Relative); 
     img.Source = bitmapImageFromUri; 

     nIndex++; 
     if (nIndex > 15) 
     { 
      nIndex = 1; 
     } 

     (sender as ToggleButton).Content = "Clear"; 
    } 

    private void ClearImageClicked(object sender, RoutedEventArgs e) 
    { 
     if (cbAvoidCache.IsChecked == true) 
     { 
      // set the UriSource to null in order to delete the image cache 
      BitmapImage bitmapImageFromUri = img.Source as BitmapImage; 
      bitmapImageFromUri.UriSource = null; 
     } 
     img.Source = null; 
     (sender as ToggleButton).Content = "Show"; 
    } 
} 

Ho anche provato a cercare altre soluzioni, alcuni risultati dei test sono le seguenti.

(1) Articolo "[wpdev] Memory leak with BitmapImage": Fornisce 2 soluzioni, una è API DisposeImage, un'altra è quella di impostare l'origine BitmapImage su null come di seguito. Anche l'articolo ci fa sapere che dobbiamo stare attenti al gestore di eventi attach/dettach, tuttavia la mia app di test non ha un gestore di eventi nella pagina di cache.

[DisposeImage]

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

[Set null]

BitmapImage bitmapImage = image.Source as BitmapImage; 
bitmapImage.UriSource = null; 
image.Source = null; 

(2) L'articolo "Windows phone: listbox with images out-of-memory": Fornisce un'API "DisposeImage" con poca differenza di (1 come di seguito, ma anche questo non funziona, ho ancora il problema di memoria.

public static void DisposeImage(BitmapImage image) 
{ 
    Uri uri= new Uri("oneXone.png", UriKind.Relative); 
    StreamResourceInfo sr=Application.GetResourceStream(uri); 
    try 
    { 
    using (Stream stream=sr.Stream) 
    { 
     image.DecodePixelWidth=1; //This is essential! 
     image.SetSource(stream); 
    } 
    } 
    catch 
    {} 
} 

(3) L'articolo "Cannot find the memory leak": fornisce le stesse 2 soluzioni come sopra accennato, anche menzionato il problema non può repro per le immagini di archiviazione isolata, tuttavia le immagini il mio test di app sono da archiviazione isolata.

(4) Ho provato anche per 1000 immagini, il risultato del test è l'arresto anomalo dell'applicazione quando l'app mostrava circa 190 immagini in sequenza, fare riferimento alla grafica di analisi dell'applicazione Windows Phone per la memoria di seguito. enter image description here

Infine, grazie per la vostra pazienza di leggere la mia domanda e la storia, ho lavorato su questo per trovare la soluzione per molti giorni. Se avete qualche indizio o soluzione, vi preghiamo gentilmente di farmelo sapere.

Grazie.

+1

Buona domanda, hanno gli stessi problemi. Qualche notizia qui? –

+0

Anche in cerca di una soluzione. Appare evidente che si tratta di un bug WP7.5, il che significa che si verifica anche su WP8 se non si seleziona solo il WP8. –

risposta

3

avevo a che fare con lo stesso problema e credo che, alla fine, che in realtà ho trovato una soluzione, io non sono un programmatore professionista, ma qui è la mia soluzione:

public Task ReleaseSingleImageMemoryTask(MyImage myImage, object control) 
    { 
     Pivot myPivot = control as Pivot; 
     Task t = Task.Factory.StartNew(() => 
     { 
      Deployment.Current.Dispatcher.BeginInvoke(() => 
      { 
       if (myImage.img.UriSource != null) 
       { 
        myImage.img.UriSource = null; 
        DisposeImage(myImage.img); 
       } 
       PivotItem it = (PivotItem)(myPivot.ItemContainerGenerator.ContainerFromIndex(myImage.number % 10)); 
       Image img = FindFirstElementInVisualTree<Image>(it); 
       if (img != null) 
       { 
        img.Source = null; 
        GC.Collect(); 
       } 
      }); 
      myImage.released = true; 
     }); 
     return t; 
    } 


private T FindFirstElementInVisualTree<T>(DependencyObject parentElement) where T : DependencyObject 
    { 
     var count = VisualTreeHelper.GetChildrenCount(parentElement); 
     if (count == 0) 
      return null; 

     for (int i = 0; i < count; i++) 
     { 
      var child = VisualTreeHelper.GetChild(parentElement, i); 

      if (child != null && child is T) 
      { 
       return (T)child; 
      } 
      else 
      { 
       var result = FindFirstElementInVisualTree<T>(child); 
       if (result != null) 
        return result; 
      } 
     } 
     return null; 
    } 

    private void DisposeImage(BitmapImage img) 
    { 
     if (img != null) 
     { 
      try 
      { 
       using (var ms = new MemoryStream(new byte[] { 0x0 })) 
       { 
        img = new BitmapImage(); 
        img.SetSource(ms); 
       } 
      } 
      catch (Exception e) 
      { 
       System.Diagnostics.Debug.WriteLine("ImageDispose FAILED " + e.Message); 
      } 
     } 
    } 

Spero che questo aiuto :)

+0

Ciao Damian, grazie per la tua risposta, anche se non sto testando questo problema ora, ancora grazie per la tua risposta. –

+0

Please help me here http://stackoverflow.com/questions/24161008/coverflow-with-out-memory – user2056563

+1

quando si tenta di disporre l'immagine si chiama 'img = new BitmapImage();'. non è ciò che sconfigge lo scopo di tutta la faccenda? – thumbmunkeys