垃圾收集无法回收BitmapImage?

Bla*_*ter 7 c# wpf bitmapimage

我有一个应用程序(WPF),它创建了大量的BitmapImages(如25000).似乎框架使用了一些内部逻辑,因此在创建之后大约消耗300 MB的内存(150个虚拟内存和150个物理内存).这些BitmapImages将添加到Image对象中,并将它们添加到Canvas中.问题是,当我释放所有那些图像时,内存不会被释放.我怎样才能释放记忆?

应用程序很简单:Xaml

    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="*"/>
            <RowDefinition Height="Auto"/>
        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
            <ColumnDefinition/>
            <ColumnDefinition/>
        </Grid.ColumnDefinitions>
        <Canvas x:Name="canvas" Grid.ColumnSpan="2"></Canvas>
        <Button Content="Add" Grid.Row="1" Click="Button_Click"/>
        <Button Content="Remove" Grid.Row="1" Grid.Column="1" Click="Remove_click"/>
    </Grid>
Run Code Online (Sandbox Code Playgroud)

代码隐藏

        const int size = 25000;
        BitmapImage[] bimages = new BitmapImage[size];
        private void Button_Click(object sender, RoutedEventArgs e)
        {
            var paths = Directory.GetFiles(@"C:\Images", "*.jpg");
            for (int i = 0; i < size; i++)
            {
                bimages[i] = new BitmapImage(new Uri(paths[i % paths.Length]));
                var image = new Image();
                image.Source = bimages[i];
                canvas.Children.Add(image);
                Canvas.SetLeft(image, i*10);
                Canvas.SetTop(image, i * 10);
            }
        }

        private void Remove_click(object sender, RoutedEventArgs e)
        {
            for (int i = 0; i < size; i++)
            {
                bimages[i] = null;
            }
            canvas.Children.Clear();
            bimages = null;
            GC.Collect();
            GC.Collect();
            GC.Collect();
        }
Run Code Online (Sandbox Code Playgroud)

这是添加图像后ResourceManager的屏幕截图 在此输入图像描述

fub*_*aar 6

Wpf中有一个错误,我们被BitmapImage对象释放的地方所咬,除非你冻结它们.http://blogs.msdn.com/b/jgoldb/archive/2008/02/04/finding-memory-leaks-in-wpf-based-applications.aspx是我们发现问题的原始页面.它应该在Wpf 3.5 sp1中修复,但在某些情况下我们仍然可以看到它.尝试更改这样的代码,看看是否是问题所在:

bimages[i] = new BitmapImage(new Uri(paths[i % paths.Length]));
bimages[i].Freeze();
Run Code Online (Sandbox Code Playgroud)

我们现在经常冻结我们的BitmapImage对象,因为我们是在探查看到其他情况下,其中WPF是听有关BitmapImage的事件,从而保持图像的活着.

如果Feeze()调用对您的代码不是一个明显的修复,我强烈建议使用一个分析器,如RedGate Memory Profiler - 它将跟踪一个依赖树,它将显示保持Image对象的内容.记忆.

  • 你有关于这个bug的任何信息来源吗? (5认同)

ole*_*sii 1

这仍然是一个数组

BitmapImage[] bimages = new BitmapImage[size];
Run Code Online (Sandbox Code Playgroud)

数组是连续的固定长度数据结构,一旦为整个数组分配了内存,就无法回收其中的一部分。尝试使用其他数据结构(例如LinkedList<T>)或其他更适合您的情况的数据结构

  • 该数组的大小将为 size * 指针大小,这不考虑所指向的对象所占用的堆空间,根据上面的示例,这些对象已全部被删除并取消引用。因此,这个说法虽然准确,但无法解释为什么垃圾回收后内存使用量没有改变。 (4认同)