WPF的Image控件如何正确释放图片资源

有一个项目是需要在后台不断地采集高清摄像头的图片的

大概是每秒3帧左右,而图片分辨率是 5472*3648, 8位深度,19.0MB

图片比较大,程序开启,只是后台采集摄像头的图片,还什么都没做,就已经吃掉1G多的内存了

现在好不容易给降到稳定在500MB内存占用左右了,但感觉和WINFORM的比较起来,简直被吊打

在程序运行时因为还会用到opencv做模板匹配,瞬间的内存峰值能达到3G左右

而使用winform的picturepox发现,内存占用连100MB都不到,这是什么鬼

而我特意将图片保存下来复制个十几份到一个文件夹中,写了一个winform和WPF的demo,都是开了一个后台线程

然后从文件夹中随机读取图片并显示到控件上,两个示例demo的内存占用WPF的比WINFORM的高五六倍...

有没有其它更好的方式呢?因为图片不能压缩,必须得完全放到Image控件上(后面因为还会对图片进行缩放,平移,绘制标记等一系列操作,就相当于一个简易的地图的功能)

 

下面是WPF的示例,一个循环

private void LoopMethod()
        {
            while (true)
            {
                try
                {
                    //获取摄像头图片
                    var bitmap = this.controller.GetCameraImage();
                    //转换为BitmapImage
                    BitmapImage newimage = new BitmapImage();
                    MemoryStream memoryStream = new MemoryStream();
                    bitmap.Save(memoryStream, System.Drawing.Imaging.ImageFormat.Bmp);
                    newimage.BeginInit();
                    newimage.CacheOption = BitmapCacheOption.OnLoad;
                    newimage.StreamSource = memoryStream;
                    newimage.EndInit();
                    newimage.Freeze();
                    bitmap.Dispose();
                    memoryStream.Dispose();

                    this.Dispatcher.Invoke(new Action(() =>
                    {
                        //图片加载到控件上
                        this.img.Source = newimage;
                    }));

                    Thread.Sleep(400);
                }
                catch
                {
                    return;
                }
                finally
                {
                    GC.Collect();
                }
            }
        }

而下面是winform的示例

 private void LoopMethod()
        {
            while (true)
            {
                //获取摄像头图片
                var bitmap = this.controller.GetCameraImage();
                this.pictureBox1.Image?.Dispose();
                this.pictureBox1.Image = bitmap;
                Thread.Sleep(400);
            }
        }

 

我尝试过使用gdi32的DeleteObject方法,但实际测试下来,没什么用,内存占用仍然没有多少改变,而且还显示不了图片,不知道是什么鬼

也试过在给Image控件赋值前先让Image.Source=null,但写不写内存也没变化就没写了

不知道怎么做才能达到WINFORM的那种效果

可以通内存泄漏工具检测一下看对象是被那里使用导致GC未回收。推荐使用.NET Memory Profiler。另外可以看看WriteableBitmap