C# 将多个项目添加到画布并使用RenderBitmapTarget进行渲染时WPF泄漏

C# 将多个项目添加到画布并使用RenderBitmapTarget进行渲染时WPF泄漏,c#,wpf,memory-leaks,C#,Wpf,Memory Leaks,我在一个服务中诊断了一个漏洞,该服务将多个图像渲染到画布上,然后在最后推出一个位图或PNG(并且多次这样做)。在启动时,该服务将猛增至600MB+然后继续增加,直到它几乎用尽了它所能掌握的一切。一旦启动,它将永远不会减少 我已经使用VS2012 perf mon检测并运行了该服务,并看到在处理完成后,有大量字节数组被放置。我已经尝试过GC清除,看看它是否会将它们清除,但没有效果。使用WinDbg查看它,我可以看到字节数组由一长串项(主要是WPF对象)控制,这些项将图像保存在ram中 我查看了MS

我在一个服务中诊断了一个漏洞,该服务将多个图像渲染到画布上,然后在最后推出一个位图或PNG(并且多次这样做)。在启动时,该服务将猛增至600MB+然后继续增加,直到它几乎用尽了它所能掌握的一切。一旦启动,它将永远不会减少

我已经使用VS2012 perf mon检测并运行了该服务,并看到在处理完成后,有大量字节数组被放置。我已经尝试过GC清除,看看它是否会将它们清除,但没有效果。使用WinDbg查看它,我可以看到字节数组由一长串项(主要是WPF对象)控制,这些项将图像保存在ram中

我查看了MSDN中所有正在使用的对象,但没有发现任何指出代码运行方式存在问题的内容

我已经整理了一些与服务密切相关的示例代码(为了方便起见减少了一些位)。这称为断开线程(设置为STA)。唯一不同的是服务代码使用MemoryStream加载来自DB的图像,而不是我正在使用的URI。这些流被处理为:

    public static void TestThread()
    {
        const int rounds = 50;
        const int innerRounds = 50;
        var randomiser = new Random(DateTime.Now.Millisecond);

        // Simulating some live values
        const float scaling = 2.67F;
        const int pageWidth = 363;
        const int pageHeight = 516;
        const int dpi = 96;

        // To simulate the live system using multiple images
        // This is an list of images of different sizes etc
        var imageList = new List<ImageData>
        {
            new ImageData{Uri = new Uri(@"..."), Height = 2592},
            new ImageData{Uri = new Uri(@"..."), Height = 1339},
            new ImageData{Uri = new Uri(@"..."), Height = 386},
            new ImageData{Uri = new Uri(@"..."), Height = 968},
            new ImageData{Uri = new Uri(@"..."), Height = 1952},
            new ImageData{Uri = new Uri(@"..."), Height = 1024},
        };

        var proc = Process.GetCurrentProcess();

        for (var i = 0; i < rounds; ++i)
        {
            var canvas = new Canvas();
            canvas.BeginInit();
            canvas.SnapsToDevicePixels = false;
            canvas.UseLayoutRounding = false;
            canvas.Width = pageWidth;
            canvas.Height = pageHeight;
            canvas.Background = Brushes.White;

            for (var j = 0; j < innerRounds; ++j)
            {
                var img = new Image {Stretch = Stretch.Fill};
                var bitmapImage = new BitmapImage();
                bitmapImage.BeginInit();
                bitmapImage.CacheOption = BitmapCacheOption.OnLoad;

                var imageNo = randomiser.Next(0, imageList.Count - 1);

                bitmapImage.UriSource = imageList[imageNo].Uri;
                int imageHeight = imageList[imageNo].Height;
                bitmapImage.DecodePixelHeight = (int) (imageHeight * scaling * 1.8);
                bitmapImage.EndInit();

                if (bitmapImage.CanFreeze)
                {
                    bitmapImage.Freeze();
                }

                var opacityMask = new ImageBrush();
                var opactityBitmap = new BitmapImage();
                opactityBitmap.BeginInit();
                opactityBitmap.CacheOption = BitmapCacheOption.OnLoad;

                imageNo = randomiser.Next(0, imageList.Count - 1);
                opactityBitmap.UriSource = imageList[imageNo].Uri;
                int opacityImageHeight = imageList[imageNo].Height; ;
                opactityBitmap.DecodePixelHeight = (int)(opacityImageHeight * scaling * 1.8);
                opactityBitmap.EndInit();

                if (opactityBitmap.CanFreeze)
                {
                    opactityBitmap.Freeze();
                }

                opacityMask.ImageSource = opactityBitmap;
                img.OpacityMask = opacityMask;

                img.Source = bitmapImage;
                img.Width = pageWidth * scaling;
                img.Height = pageHeight * scaling;
                Canvas.SetLeft(img, 0);
                Canvas.SetTop(img, 0);
                canvas.Children.Add(img);
                img.Opacity = 50F;
            }

            canvas.LayoutTransform = null;
            var size = new Size(Math.Max(canvas.Width, 5), Math.Max(canvas.Height, 5));
            canvas.Measure(size);
            canvas.Arrange(new Rect(size));
            canvas.EndInit();

            var renderTargetBitmap = new RenderTargetBitmap(pageWidth, pageHeight, dpi, dpi, PixelFormats.Default); //xxx

            renderTargetBitmap.Render(canvas);

            if (renderTargetBitmap.CanFreeze)
            {
                renderTargetBitmap.Freeze();
            }

            System.Drawing.Image imageData;
            using (var ms = new MemoryStream())
            {
                var image = new PngBitmapEncoder();
                image.Frames.Add(BitmapFrame.Create(renderTargetBitmap));
                image.Save(ms);
                imageData = System.Drawing.Image.FromStream(ms);
            }


            var encoder = Encoder.Quality;
            var encoderParams = new EncoderParameters(1);
            encoderParams.Param[0] = new EncoderParameter(encoder, 100L);

            ImageCodecInfo[] codecs = ImageCodecInfo.GetImageDecoders();
            var codecInfo = codecs.FirstOrDefault(x => x.FormatID == ImageFormat.Png.Guid);

            Byte[] bitmapArray;
            using (var ms = new MemoryStream())
            {
                imageData.Save(ms, codecInfo, encoderParams);
                bitmapArray = ms.GetBuffer();
            }

            var filepath = string.Format(@"C:\temp\{0}.png", i);
            imageData.Save(filepath, ImageFormat.Png);

            var gcMemory = GC.GetTotalMemory(false) / 1024;
            Console.WriteLine("Proc mem = {0}KB, GC = {1}KB", (proc.PrivateMemorySize64 / 1024), gcMemory);
        }

        Console.WriteLine("Exiting");
    }
publicstaticvoidtestthread()
{
常数整数轮=50;
内部循环常数=50;
var randomiser=新随机数(DateTime.Now.毫秒);
//模拟某些活动值
恒浮标度=2.67F;
常量int pageWidth=363;
常数int pageHeight=516;
常数int dpi=96;
//使用多个图像模拟实时系统
//这是不同大小的图像列表等
var imageList=新列表
{
新图像数据{Uri=newuri(@“…”),高度=2592},
新图像数据{Uri=newuri(@“…”),高度=1339},
新图像数据{Uri=newuri(@“…”),高度=386},
新图像数据{Uri=newuri(@“…”),高度=968},
新图像数据{Uri=newuri(@“…”),高度=1952},
新图像数据{Uri=newuri(@“…”),高度=1024},
};
var proc=Process.GetCurrentProcess();
对于(变量i=0;ix.FormatID==ImageFormat.Png.Guid);
字节[]位图数组;
使用(var ms=new MemoryStream())
{
保存(ms、codecInfo、encoderParams);
bitmapArray=ms.GetBuffer();
}
var filepath=string.Format(@“C:\temp\{0}.png”,i);
保存(文件路径,ImageFor