C# 异步上载多个图像并调整其大小时出现内存不足异常
您好,我正在尝试异步上传一些图像,我遇到内存不足异常,我正在使用语句进行处理,但我得到以下堆栈跟踪C# 异步上载多个图像并调整其大小时出现内存不足异常,c#,asp.net-mvc,asynchronous,async-await,azure-storage-blobs,C#,Asp.net Mvc,Asynchronous,Async Await,Azure Storage Blobs,您好,我正在尝试异步上传一些图像,我遇到内存不足异常,我正在使用语句进行处理,但我得到以下堆栈跟踪 [OutOfMemoryException: Out of memory.] System.Drawing.Graphics.CheckErrorStatus(Int32 status) +1146420 System.Drawing.Graphics.DrawImage(Image image, Rectangle destRect, Int32 srcX, Int32 srcY,
[OutOfMemoryException: Out of memory.]
System.Drawing.Graphics.CheckErrorStatus(Int32 status) +1146420
System.Drawing.Graphics.DrawImage(Image image, Rectangle destRect, Int32 srcX, Int32 srcY, Int32 srcWidth, Int32 srcHeight, GraphicsUnit srcUnit, ImageAttributes imageAttrs, DrawImageAbort callback, IntPtr callbackData) +256
System.Drawing.Graphics.DrawImage(Image image, Rectangle destRect, Int32 srcX, Int32 srcY, Int32 srcWidth, Int32 srcHeight, GraphicsUnit srcUnit, ImageAttributes imageAttr) +48
这是resizer,在这里我得到异常:
public Bitmap ResizeImage(Image image, int width, int height)
{
var newWidth = (int)(imageWidth * ratio) < 210 ? 210 : (int)(imageWidth * ratio);
var newHeight = (int)(imageHeight * ratio) < 210 ? 210 : (int)(imageHeight * ratio);
//Image resize logic
var destRect = new Rectangle(0, 0, newWidth, newHeight);
var destImage = new Bitmap(newWidth, newHeight);
destImage.SetResolution(image.HorizontalResolution, image.VerticalResolution);
using (var graphics = Graphics.FromImage(destImage))
{
graphics.CompositingMode = CompositingMode.SourceCopy;
graphics.CompositingQuality = CompositingQuality.HighQuality;
graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
graphics.SmoothingMode = SmoothingMode.HighQuality;
graphics.PixelOffsetMode = PixelOffsetMode.HighQuality;
using (var wrapMode = new ImageAttributes())
{
wrapMode.SetWrapMode(WrapMode.TileFlipXY);
/*Here I get error*/graphics.DrawImage(image, destRect, 0, 0, image.Width, image.Height, GraphicsUnit.Pixel,
wrapMode);
}
}
return destImage;
}
公共位图大小图像(图像图像、整数宽度、整数高度)
{
var newWidth=(int)(图像宽度*比率)<210?210:(int)(图像宽度*比率);
var newHeight=(int)(图像高度*比率)<210?210:(int)(图像高度*比率);
//图像调整逻辑
var destect=新矩形(0,0,newWidth,newHeight);
var destImage=新位图(新宽度、新高度);
Destinmage.SetResolution(图像.水平分辨率,图像.垂直分辨率);
使用(var graphics=graphics.FromImage(destImage))
{
graphics.CompositingMode=CompositingMode.SourceCopy;
graphics.CompositingQuality=CompositingQuality.HighQuality;
graphics.InterpolationMode=InterpolationMode.HighQualityBicubic;
graphics.SmoothingMode=SmoothingMode.HighQuality;
graphics.PixelOffsetMode=PixelOffsetMode.HighQuality;
使用(var wrapMode=newImageAttributes())
{
wrapMode.SetWrapMode(wrapMode.TileFlipXY);
/*这里我得到错误*/graphics.DrawImage(image,desect,0,0,image.Width,image.Height,GraphicsUnit.Pixel,
wrapMode);
}
}
返回目标图像;
}
此处是上载图像的位置:
private async Task<short> UploadImage(string title, HttpPostedFileBase file, short dimensionWidth,
short dimensionHeight)
{
var blockBlob = CloudBlobContainer.GetBlockBlobReference(title);
var jpgInfo = ImageCodecInfo.GetImageEncoders().First(codecInfo => codecInfo.MimeType == "image/jpeg");
using (var image = Image.FromStream(file.InputStream, true, true))
{
using (var stream = new MemoryStream())
using (var encParams = new EncoderParameters(1))
{
encParams.Param[0] = new EncoderParameter(Encoder.Quality, 60L);
if (image.Width > dimensionWidth && image.Height > dimensionHeight)
using (Bitmap bitMapImage = ResizeImage(image, dimensionWidth, dimensionHeight))
{
bitMapImage.Save(stream, jpgInfo, encParams);
}
else
{
image.Save(stream, jpgInfo, encParams);
}
stream.Position = 0;
await blockBlob.UploadFromStreamAsync(stream);
blockBlob.Properties.CacheControl = "public, max-age=864000";
blockBlob.SetProperties();
}
}
return (short)EnumData.EOpStatus.Success;
}
private async Task UploadImage(字符串标题、HttpPostedFileBase文件、短维度宽度、,
短尺寸(高度)
{
var blockBlob=CloudBlobContainer.getblockblobbreference(title);
var jpgInfo=ImageCodecInfo.GetImageEncoders().First(codecInfo=>codecInfo.MimeType==“image/jpeg”);
使用(var image=image.FromStream(file.InputStream,true,true))
{
使用(var stream=new MemoryStream())
使用(var encParams=新编码器参数(1))
{
encParams.Param[0]=新编码器参数(编码器质量,60L);
if(image.Width>dimensionWidth&&image.Height>dimensionHeight)
使用(位图bitMapImage=ResizeImage(图像、尺寸宽度、尺寸高度))
{
保存(流、jpgInfo、encParams);
}
其他的
{
保存(流、jpgInfo、encParams);
}
流位置=0;
等待blockBlob.UploadFromStreamAsync(流);
blockBlob.Properties.CacheControl=“public,最大年限=864000”;
blockBlob.SetProperties();
}
}
返回(短)EnumData.EOpStatus.Success;
}
主要功能如下:
public async Task<string> UploadImages(string title, IEnumerable<HttpPostedFileBase> files, short fileCount)
{
var fileIndex = 0;
var imageCsv = String.Empty;
var uploadTask = new Task<short>[fileCount * 2];
foreach (var file in files)
{
var fullTitle = title + "-" + Convert.ToString(fileIndex) + Path.GetExtension(file.FileName);
uploadTask[fileIndex] = UploadImage(fullTitle, file, 1440, 900);
uploadTask[fileIndex + 1] = UploadImage("thumb-" + fullTitle, file, 280, 280);
imageCsv += String.IsNullOrEmpty(imageCsv) ? fullTitle : "," + fullTitle;
/*await Task.WhenAll(uploadTask[fileIndex], uploadTask[fileIndex + 1]);*///Works fine in this case
fileIndex += 2;
}
await Task.WhenAll(uploadTask);
return imageCsv;
}
公共异步任务上载映像(字符串标题、IEnumerable文件、短文件计数)
{
var fileIndex=0;
var imageCsv=String.Empty;
var uploadTask=新任务[fileCount*2];
foreach(文件中的var文件)
{
var fullTitle=title+“-”+Convert.ToString(fileIndex)+Path.GetExtension(file.FileName);
uploadTask[fileIndex]=UploadImage(完整标题,文件,1440900);
uploadTask[fileIndex+1]=UploadImage(“thumb-”+fullTitle,文件,280280);
imageCsv+=String.IsNullOrEmpty(imageCsv)?fullTitle:“,”+fullTitle;
/*wait Task.whalll(uploadTask[fileIndex],uploadTask[fileIndex+1]);*///在这种情况下可以正常工作
fileIndex+=2;
}
等待任务。WhenAll(上传任务);
返回图像CSV;
}
所以在一些上传之后,我得到了一个错误
性能监视器在整个应用程序使用过程中似乎都很正常,我认为它很正常
我相信您确实在尝试在目标矩形之外绘制。。。如果您注意到您的代码,您实际上(在标记的行中)正在绘制
image.Width
和image.Height
(原始尺寸),而不是应用的维度比率…在作业完成后处理sourceImage和DesImage。是否尝试运行Visual Studio的内存分析工具?这可能不是实际的OOM错误。GDI+喜欢在传递无效参数时返回这样的错误。@Micky nope现在尝试使用性能监视器,但这提醒了我-GDI对象有一个限制,不管您有多少可用RAM。虽然在使用GDI(位图只是其包装器)时,您似乎在管理它们方面做得相当好,OutOfMemoryException
最好命名为outofhandleexception
或OutOfUnManagedMemoryException
,但它通常与CLR分配的#字节无关。这都是非托管内存和GDI句柄。然而,查看您的代码,我没有看到任何明显的错误会导致内存或句柄泄漏。你是在处理非常大的图像吗?我想你是在拍摄drawImage?我们应该从整个图像而不是固定的图像中进行绘制,出于好奇,这里请查看链接,只需尝试graphics.DrawImage(图像,析取,0,0,50,50,GraphicsUnit.Pixel,wrapMode)代码>但是我建议的固定大小呢?同样的例外?你尝试了固定尺寸,即200、50和正常尺寸。你的答案在我看来还行,但你能解释一下为什么这样做,或者提供一个代码片段如何做到这一点吗?这将使这篇文章的未来访问者更容易找到他们的解决方案。谢谢