Потребление памяти управления BitmapImage / Image в Windows Phone 8

Я тестирую приложение WP8, и это просмотрщик изображений, чтобы показать много изображений, я обнаружил, что потребление памяти приложения растет и хочет узнать, как его решить.

Я читал некоторые статьи из интернета, однако решения эти статьи не работают на моем приложении, пожалуйста, прочитайте ниже историю.

во-первых, я нашел в статье "советы по изображению для Windows Phone 7 " и загрузите его образец, чтобы выполнить тестирование чистого кэша изображений, он работает с 1 изображение.

и затем для целей тестирования, я делаю это приложение скомпилировано с 15 автономных образов внутри приложения, и установить как "содержание", Пожалуйста, загрузите тестовое приложение из здесь.

мои шаги тестирования являются:

(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

когда я тестирую свое приложение, память поднимается, как 16.02 MB => показать (19.32 MB) => очистить ( 16.15 MB) = > показать (20.18 MB) = > очистить (17.03 MB)...так далее И память не освободитесь, даже оставив страницу кэширования, и снова перейдите на страницу кэширования. Кажется, решение статьи "советы по изображению для Windows Phone 7" работает только для 1 изображения.

вот xaml и код-за решением"советы по изображению для Windows Phone 7".

[кэширования.язык 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>

[кэширования.код 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";
    }
}

Я также попытался найти любые другие решения, некоторые результаты тестирования таковы под.

(1) статья "[wpdev] утечка памяти с BitmapImage": он предоставляет 2 решения, один-DisposeImage API, другой-установить источник BitmapImage в null, как показано ниже. Также в статье мы должны быть осторожны с обработчиком событий attach / dettach, однако мое приложение для тестирования не имеет обработчика событий на странице кэширования.

[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) статьи "Windows phone: список с изображениями из памяти": он предоставляет API "DisposeImage" с небольшой разницей, чем (1), как показано ниже, но это также не работает, у меня все еще есть симптом повышения памяти.

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) Статья "не удается найти утечку памяти": он предоставляет те же 2 решения, что и выше, также он упомянул, что проблема не может повторять изображения изолированного хранилища, однако изображения моего тестового приложения из изолированных место хранения.

(4) я также пробовал для 1000 изображений, результат тестирования-сбой приложения, когда приложение показало около 190 изображений последовательно, обратитесь к графическому анализу приложений Windows Phone для памяти ниже. enter image description here

наконец, спасибо за ваше терпение, чтобы прочитать мой вопрос и историю, я работал над этим, чтобы найти решение в течение многих дней. Если у вас есть какие-либо подсказки или решения, пожалуйста, сообщите мне об этом.

спасибо.

1 ответов


Я имел дело с той же проблемой, и я думаю, в конце концов, что на самом деле я нашел решение, я не профи программист, но вот мое решение:

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

надеюсь, что это поможет :)