ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

并行运行多个图像操作导致OutOfMemory异常

2019-12-01 07:18:22  阅读:185  来源: 互联网

标签:multithreading out-of-memory asp-net c asp-net-mvc


我在一个网站上工作,我需要能够将4000×6000左右的图像分割并成像为4个部分(包括许多其他任务),并且我需要尽快对多个用户进行处理.

我目前执行此操作的代码是

var bitmaps = new RenderTargetBitmap[elements.Length];

using (var stream = blobService.Stream(key))
{
    BitmapImage bi = new BitmapImage();
    bi.BeginInit();
    bi.StreamSource = stream;
    bi.EndInit();

    for (var i = 0; i < elements.Length; i++)
    {
        var element = elements[i];

        TransformGroup transformGroup = new TransformGroup();
        TranslateTransform translateTransform = new TranslateTransform();
        translateTransform.X = -element.Left;
        translateTransform.Y = -element.Top;
        transformGroup.Children.Add(translateTransform);

        DrawingVisual vis = new DrawingVisual();
        DrawingContext cont = vis.RenderOpen();
        cont.PushTransform(transformGroup);
        cont.DrawImage(bi, new Rect(new Size(bi.PixelWidth, bi.PixelHeight)));
        cont.Close();

        RenderTargetBitmap rtb = new RenderTargetBitmap(element.Width, element.Height, 96d, 96d, PixelFormats.Default);
        rtb.Render(vis);
        bitmaps[i] = rtb;
    }
}

for (var i = 0; i < bitmaps.Length; i++)
{
    using (MemoryStream ms = new MemoryStream())
    {
        PngBitmapEncoder encoder = new PngBitmapEncoder();
        encoder.Frames.Add(BitmapFrame.Create(bitmaps[i]));
        encoder.Save(ms);
        var regionKey = WebPath.Variant(key, elements[i].Id);
        saveBlobService.Save("image/png", regionKey, ms);
    }
}

我正在运行多个线程,这些线程使工作脱离队列.我发现如果这部分代码一次被4个线程击中,则会收到OutOfMemory异常.我可以通过将以上所有代码包装在lock(obj)中来阻止这种情况的发生,但这并不理想.我试过只包装第一个using块(从磁盘读取文件并拆分),但是我仍然遇到内存不足的异常(这部分代码执行得非常快).

>考虑到应该占用的内存量,我这很正常吗?
>我可以进行任何优化吗?
>我可以增加可用内存吗?

更新:

我根据Moozhe的帮助编写的新代码

public static void GenerateRegions(this IBlobService blobService, string key, Element[] elements)
{
    using (var stream = blobService.Stream(key))
    {
        foreach (var element in elements)
        {
            stream.Position = 0;
            BitmapImage bi = new BitmapImage();
            bi.BeginInit();
            bi.SourceRect = new Int32Rect(element.Left, element.Top, element.Width, element.Height);
            bi.StreamSource = stream;
            bi.EndInit();

            DrawingVisual vis = new DrawingVisual();
            DrawingContext cont = vis.RenderOpen();
            cont.DrawImage(bi, new Rect(new Size(element.Width, element.Height)));
            cont.Close();

            RenderTargetBitmap rtb = new RenderTargetBitmap(element.Width, element.Height, 96d, 96d, PixelFormats.Default);
            rtb.Render(vis);

            using (MemoryStream ms = new MemoryStream())
            {
                PngBitmapEncoder encoder = new PngBitmapEncoder();
                encoder.Frames.Add(BitmapFrame.Create(rtb));
                encoder.Save(ms);
                var regionKey = WebPath.Variant(key, element.Id);
                blobService.Save("image/png", regionKey, ms);
            }
        }
    }
}

解决方法:

如果您尝试并行调用4000×6000图像的DrawImage,则会遇到麻烦.您将其裁剪为时已晚,到将其呈现到RenderTargetBitmap时,它已经在内存中呈现为完整大小.

不要像使用转换那样裁剪图像源,而是尝试使用BitmapImage.SourceRect属性,如下所示:

BitmapImage.SourceRect =新的Rect(element.Left,element.Top,element.Width,element.Height);

您可能想在调用BeginInit()之前尝试将其放置,然后完全摆脱转换.

编辑:实际上,在您的情况下,您必须在for循环的每次迭代中更改SourceRect.请记住,必须将DrawImage中的Size参数更改为元素大小.

标签:multithreading,out-of-memory,asp-net,c,asp-net-mvc
来源: https://codeday.me/bug/20191201/2079253.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有