1

我一直在努力诊断服务中的泄漏,该服务将多个图像渲染到画布上,然后在最后推出位图或 PNG(并多次执行此操作)。在启动时,该服务将飙升至 600MB+,然后继续增加,直到它几乎占用了它可以掌握的所有内容。一旦开始,它就永远不会减少。

我已经使用 VS2012 perf mon 检测并运行了该服务,并且看到在处理完成后有大量的字节数组放置。我已经尝试过 GC clear 看看它是否会清除它们无济于事。使用 WinDbg 查看它,我可以看到字节数组被一长串项目(主要是 WPF 对象)保存在内存中。

我查看了 MSDN 中所有正在使用的对象,但找不到任何指出代码运行方式存在问题的东西。

我整理了一些与服务密切相关的示例代码(为了方便起见,减少了一些位)。这被称为线程(设置为 STA)。唯一的其他区别是服务代码使用 MemoryStreams 加载来自数据库而不是我正在使用的 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");
    }

我希望这很明显我在这里失踪了。感谢你的帮助!

4

0 回答 0