2012-11-13 22 views
8

Ich habe an einer WP7-App gearbeitet, es ist eine Bildergalerie-App, mit grundlegenden Zoom-und Flick-Gesten implementiert.Kann das Speicherleck nicht finden

Für Testzwecke kompilierte ich die App mit Offline-Bildern (ihre Dateinamen sind nummeriert) auf Inhalt und Zugriff auf sie über hart codierte Zeichenfolge (die später ersetzt wird).

Aber kam zu der Erkenntnis, dass App eine Menge Speicher verbraucht. Ich dachte, es war aufgrund von Bildern und gefunden this blog; Bilder wurden immer zwischengespeichert. Ich habe den Code aus dem Blog verwendet, um dies zu korrigieren. Still-Speicher wird nicht freigegeben, obwohl die Verbrauchsrate gesunken ist.

Für letzten Versuch habe ich einen weiteren Test-App mit Grundzug 2-Taste für die Navigation und Bildsteuerung für Bilder, nur um sicher zu machen, es war nicht meine Geste Codes, die das Problem sein könnte.

Dies ist der 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> 

Das sind die CS-

Datei ist
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); 
    } 

Aber noch ist Speicherleck gibt und ich kann Punkt nicht stecken. Es fällt mir schwer, es zu finden. Speicherprofiler zeigt, dass ich viele Instanzen einer Zeichenfolge habe, und ich kann das nicht interpretieren.

Nur wenige Punkte:

  • Ich habe Bilder in einem Ordner "000" und dem Namen "Bild ###". Derzeit habe ich Bilder mit Dateinamen von „image001“ auf „image042“
  • Test-App einen Speicherbedarf von 6 MB hat, sobald er die erste Seite vollständig mit dem Bild zeigt, und nach fisrt Seitenwechseln steigt es auf fast 18-20 MB
  • Folgeseitenwechsel Ergebnis einer allmählichen Zunahme der Speicher und dann schließlich abstürzen, wenn die Zahl der Bilder erlauben, sonst nach durch alle Bilder der Speicherverbrauch Radfahren ist konstant
  • I JPG-Dateien mit ca. Dimension 1280 bin mit x 2000, zum Testen skaliere ich keine Bilder.

Heap Summary -> New Allocations

+0

Erzeugen Sie einen zusätzlichen Thread für jedes angezeigte Bild, um es zu rendern? Sie haben 1918 Thread-Objekte herum. Das hört sich nicht gesund an. Finden Sie heraus, wie Sie die Threads erstellen und ordnungsgemäß terminieren, damit die zugeordneten Ressourcen, auf die von der Thread-Methode verwiesen wird, freigegeben werden können. –

+0

@Alois, ich bin kein Profi, nur ein Hobby-Entwickler. Ich habe wirklich keine Ahnung, wo ich versehentlich Fäden erzeuge. Ich erstelle keine Threads explizit. Ich weiß nicht mal, ist das wirklich ein Problem. Was ich sagen kann ist, dass der gesamte Code meiner Beispiel-App angezeigt wird. Also vielleicht, wenn du es neu erstellen könntest, sieh es dir an. Wäre hilfreich. –

Antwort

5

ich die gleiche Art von App haben, mit den nächsten/vorherigen Bild Tasten. Und ich hatte genau das gleiche Speicherleck, was mich verrückt gemacht hat.

Ich habe immer noch nicht in der Lage gewesen, um die Ursache zu finden, aber ich habe es geschafft, es mit einem hässlichen Hack umgehen.Bei der Anzeige des nächsten Bildes zwinge ich die alte Bildquelle dazu, ein ungültiges Bild zu laden, wodurch der Speicher freigegeben wird. Ich verstehe nicht, warum das Entfernen aller Referenzen und das Aufrufen des Garbage Collectors nicht genug ist, da muss irgendwo eine andere Referenz intern gespeichert werden.

Wie auch immer, hier ist der Hack:

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

Sie können in Ihrer RefreshImage Methode es zum Beispiel nennen:

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 beschämt, dass zu verwenden, aber zumindest scheint es zu funktionieren.

+0

Ich war auf der Suche nach dir. Ich sehe dich als eines der aktiveren Mitglieder im WP7-Bereich. SO könnte einen PM-Dienst bereitstellen. Wie auch immer, die von Ihnen vorgeschlagene Lösung scheint richtig zu sein. Ich selbst hatte daran gedacht. Ich werde es als eine Antwort markieren, aber ich werde es nicht bestätigen. Siehe meine eigene Antwort dafür. Aber danke für Hilfe. –

1

Ich habe Ihre Codebeispiel versucht, aber in Windows-Umgebung Phone 8 und ich konnte das Leck nicht reproduzieren. Der einzige Unterschied ist, dass ich meine eigenen Bilder verwendet habe.

Die aktuelle Speicherauslastung blieb bei 13MB für meinen 512 WVGA-Emulator und die Peak bei 14MB geblieben. Ich habe den "nächsten Knopf" etwa 20 Mal gedrückt.

Haben Sie auch versucht, Bindings für ImageHolder zu verwenden, anstatt die Quelle manuell einzustellen?

(übrigens, ich sehe keine möglichen Speicherlecks in Ihrem Codebehind).

(auch diesen Artikel überprüfen http://blogs.windows.com/windows_phone/b/wpdev/archive/2012/02/01/memory-profiling-for-application-performance.aspx)

+0

"visuell sehe ich keine möglichen Speicherlecks in Ihrem Codebehind"; das verwirrt mich. Versuchen Sie Datenbindung, danke für die Antwort. –

1

Nach vielen Probeläufen und Debugging-Sitzungen habe ich festgestellt, dass dieses Zwischenspeichern von Bildern nicht ausgeführt wird (oder nicht so aggressiv durchgeführt wird), wenn Bilder im IsolatedStorage der App gespeichert sind.

Sache ist, dass ich die Bilder, die ein Teil der XAP-Datei waren, als Inhalt verwendet wurde. Ich habe das gemacht, weil ich nur meinen Bildbetrachter testen wollte. Aber das wäre nicht der Fall, wenn meine App fertig wäre. App wurde wirklich entworfen, um Bilder in isoliertem Speicher zu speichern und sie anzuzeigen.

Also habe ich den notwendigen Code eingerichtet und voila, Bilder werden jetzt Müll gesammelt, obwohl sie noch im Cache gespeichert wurden. Siehe Bild unten (siehe wie oft Garbage Collector aufgerufen wird). Das ist eine Lösung für eine nicht so triviale Frage, deshalb hat niemand sonst ein Problem dieser Art gesehen.

Ich glaube, wenn WP7 silverlight findet, dass Bilder nicht aus isoliertem Speicher stammen, nimmt es an, dass Bild von einem Remote-URI stammt und beschließt, es dennoch zwischenzuspeichern. Und hier setzt Silverlight Image Caching ein. Wie eine andere Antwort bestätigt, passiert dies in WP8 nicht. enter image description here