Zużycie pamięci BitmapImage / Kontrola obrazu w Windows Phone 8

Testuję aplikację WP8 i przeglądarkę obrazów, aby pokazać wiele obrazów. Znalazłem zużycie pamięci w aplikacji, która rośnie, i chcę dowiedzieć się, jak ją rozwiązać.

Przeczytałem kilka artykułów z internetu, jednak rozwiązania dostarczane przez te artykuły nie działają w mojej aplikacji. Przeczytaj historię poniżej.

Najpierw znalazłem artykuł „Porady dotyczące obrazów dla Windows Phone 7„i pobierz jego próbkę, aby przetestować czystą pamięć podręczną obrazu, działa z1 obraz.

Następnie do celów testowych kompiluję tę aplikację15 obrazów offline w aplikacji i ustaw jako „Treść”, pobierz aplikację testową ztutaj.

Moje kroki testowe to:

(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

Podczas testowania mojej aplikacji rośnie pamięć16,02 MB => Pokaż (19,32 MB) => Wyczyść (16,15 MB) => Pokaż (20,18 MB) => Wyczyść (17,03 MB) ... itd. Pamięć nie zostanie zwolniona, nawet pozostawiając stronę buforowania i przejdź ponownie do strony buforowania. Wydaje się, że rozwiązaniem jest artykułPorady dotyczące obrazów dla Windows Phone 7„działa tylko1 obraz.

Nadchodzi xaml i kodowanie rozwiązania przez „Porady dotyczące obrazów dla 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";
    }
}

Próbowałem również przeszukiwać inne rozwiązania, niektóre wyniki testów są następujące.

(1) Artykuł „[wpdev] Przeciek pamięci z BitmapImage„: Dostarcza 2 rozwiązania, jednym z nich jest API DisposeImage, innym jest ustawianie źródła BitmapImage na null jak poniżej. Również artykuł informuje nas, że musimy uważać na dołączanie / dettowanie obsługi zdarzeń, jednak moja aplikacja testująca nie ma obsługi zdarzeń na stronie buforowania.

[DisposeImage]

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

[Ustaw null]

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

(2) Artykuł „Windows phone: listbox z obrazami poza pamięcią„: Dostarcza API„ DisposeImage ”z niewielką różnicą niż (1) jak poniżej, ale to również nie działa, nadal mam symptom podnoszenia pamięci.

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) Artykuł „Nie można znaleźć przecieku pamięci„: Zapewnia te same dwa rozwiązania, o których wspomniano powyżej, wspomniał również, że problem nie może ponowić obrazów pojedynczych magazynów, jednak obrazy mojej aplikacji testowej pochodzą z izolowanego magazynu.

(4) Próbowałem również na 1000 obrazów, wynik testu to awaria aplikacji, gdy aplikacja pokazywała około 190 obrazów sekwencyjnie, proszę zapoznać się z grafiką analizy aplikacji Windows Phone dla pamięci poniżej.

Wreszcie, dzięki za cierpliwość, aby przeczytać moje pytanie i historię, pracuję nad tym, aby znaleźć rozwiązanie na wiele dni. Jeśli masz jakąś wskazówkę lub rozwiązanie, proszę daj mi znać.

Dzięki.

questionAnswers(1)

yourAnswerToTheQuestion