C# 使用.Clone()剪切位图时内存不足
我试图从用户上传的图像中自动生成缩略图,但我总是遇到“内存不足”的异常情况。 据我所知,当您指定图像外部的起始位置或宽度/高度时,即使我这样做,也会引发内存不足异常C# 使用.Clone()剪切位图时内存不足,c#,asp.net,.net,C#,Asp.net,.net,我试图从用户上传的图像中自动生成缩略图,但我总是遇到“内存不足”的异常情况。 据我所知,当您指定图像外部的起始位置或宽度/高度时,即使我这样做,也会引发内存不足异常 var rct = new Rectangle(5, 5, 10, 10); var whatever = bitmap.Clone(rct, bitmap.PixelFormat); 在800x900像素的图像上,我仍然会遇到“内存不足”的异常,我无法找出它的问题所在,也无法从其他线程中得到任何好的答案,因为所有关于OOM异常的
var rct = new Rectangle(5, 5, 10, 10);
var whatever = bitmap.Clone(rct, bitmap.PixelFormat);
在800x900像素的图像上,我仍然会遇到“内存不足”的异常,我无法找出它的问题所在,也无法从其他线程中得到任何好的答案,因为所有关于OOM异常的事情都是超出图像边界的错误。
有人对此有解释或解决办法吗
编辑:更多的上下文
图像的循环
foreach (var blob in fileInfoList)
{
var blockBlobName = CheckExistence(BaseBlobUrl, blob.FileName, blob.FileNameWithoutExtension);
var image = new Image()
{
BlobUrl = Path.Combine(BaseBlobUrl, blockBlobName),
FullName = blob.FileName,
FileName = blob.FileNameWithoutExtension,
BlockBlobName = blockBlobName,
OwningOrganizationId = CurrentUser.UserOrganization.OrganizationId,
ThumbnailUrl = CreateThumbnail(blob.File, blockBlobName),
Name = "Whatever"
};
blobList.Add(image);
RepositoryFactory.AzureStorageRepository.SaveImage(blob.File, blockBlobName, blob.ContentType, CurrentUser.UserOrganization.Organization.Id);
}
由列表中的每个图像调用以生成缩略图的方法
public string CreateThumbnail(byte[] b, string parentImageName)
{
Bitmap bmp;
using (var ms = new MemoryStream(b))
{
bmp = new Bitmap(ms);
}
Bitmap thumbnail = bmp;
Rectangle rect = new Rectangle(5, 5, 10, 10);
if (bmp.Width > bmp.Height)
thumbnail = bmp.Clone(rect, bmp.PixelFormat);
else if (bmp.Height > bmp.Width)
thumbnail = bmp.Clone(new Rectangle((bmp.Height/2) - (bmp.Width/2), 0, bmp.Width, bmp.Width), bmp.PixelFormat);
byte[] bmpArray = new byte[0];
using (var ms = new MemoryStream())
{
finalCrop.Save(ms, System.Drawing.Imaging.ImageFormat.Jpeg);
ms.Close();
bmpArray = ms.ToArray();
}
var name = "Thumbnail_" + parentImageName;
RepositoryFactory.AzureStorageRepository.SaveThumbnail(bmpArray, name, "jpg/image", CurrentUser.UserOrganization.Organization.Id);
return BaseBlobUrl + "thumbnails/" + name;
}
我认为你遇到的问题是位图需要处理。如果一个人在没有释放其底层非托管内容(即被处置)的情况下被垃圾收集,那么该内存将无法恢复 还请注意,您需要处理这两个位图。最好的做法是将它们包装在一个容器中,如下所示:
using (var ms = new MemoryStream(b))
{
using (Bitmap bmp = new Bitmap(ms))
using (Bitmap thumbnail = bmp)
{
Rectangle rect = new Rectangle(5, 5, 10, 10);
if (bmp.Width > bmp.Height)
thumbnail = bmp.Clone(rect, bmp.PixelFormat);
else if (bmp.Height > bmp.Width)
thumbnail = bmp.Clone(new Rectangle((bmp.Height / 2) - (bmp.Width / 2), 0, bmp.Width, bmp.Width), bmp.PixelFormat);
byte[] bmpArray = new byte[0];
using (var ms = new MemoryStream())
{
finalCrop.Save(ms, System.Drawing.Imaging.ImageFormat.Jpeg);
ms.Close();
bmpArray = ms.ToArray();
}
var name = "Thumbnail_" + parentImageName;
RepositoryFactory.AzureStorageRepository.SaveThumbnail(bmpArray, name, "jpg/image", CurrentUser.UserOrganization.Organization.Id);
return BaseBlobUrl + "thumbnails/" + name;
}
}
值得注意的是,
使用
将调用其目标上的Dispose()
,即使抛出异常(因此具有与@Scott Chamberlain answer相同的最终
类型功能好的,因此我通过处理位图找到了问题的答案。
在这段代码之后
Bitmap thumbnail = bmp;
我补充说
bmp.Dispose();
在调试过程中,我注意到bmp中的所有属性都没有保留在名为缩略图的位图中,因此我将其更改为以下内容
Bitmap thumbnail = new Bitmap(bmp);
感谢大家告诉我如何处置位图!以下是正确处置对象的方法
Bitmap bmp = null;
Bitmap thumbnail = null;
try
{
using (var ms = new MemoryStream(b))
{
bmp = new Bitmap(ms);
}
Rectangle rect = new Rectangle(5, 5, 10, 10);
if (bmp.Width > bmp.Height)
thumbnail = bmp.Clone(rect, bmp.PixelFormat);
else if (bmp.Height > bmp.Width)
thumbnail = bmp.Clone(new Rectangle((bmp.Height/2) - (bmp.Width/2), 0, bmp.Width, bmp.Width), bmp.PixelFormat);
else
thumbnail = bmp;
byte[] bmpArray = new byte[0];
using (var ms = new MemoryStream())
{
finalCrop.Save(ms, System.Drawing.Imaging.ImageFormat.Jpeg);
ms.Close();
bmpArray = ms.ToArray();
}
var name = "Thumbnail_" + parentImageName;
RepositoryFactory.AzureStorageRepository.SaveThumbnail(bmpArray, name, "jpg/image", CurrentUser.UserOrganization.Organization.Id);
return BaseBlobUrl + "thumbnails/" + name;
}
finally
{
if(bmp != null)
bmp.Dispose();
if(thumbnail != null)
thumbnail.Dispose(); //If bmp and thumbnail are the same object this is still safe to do.
}
使用try/finally块确保即使在发生错误的情况下也能处理对象。执行额外的
位图缩略图=新位图(bmp)
在您的答案中,只会生成一个您忘记处理的额外位图。您是在循环中执行此操作的,不是吗?生成缩略图的方法是从循环中调用的,因为用户可以同时上载多个图像。您是否可以提供更多的代码,包括循环上下文请注意,您从来都不是Dis姿势
ing图像/位图;这是一个非常糟糕的主意,因为有大量与对象相关的本机资源,其中一些资源非常有限(例如GDI+句柄).GDI+并非真正设计用于服务器,因此请小心。您尝试过的所有图像都会出现问题吗?我无法再现您看到的问题,请注意,GDI+中的OOM可能意味着许多不同的错误,而不仅仅是OOM或边界错误。您到底从何处获得异常?您似乎没有处理位图您可以在任何位置创建。除非您将位图返回到某个位置,否则您应该为位图添加一个using
块。我可以使用using
块,或者将bmp.Dispose()放入
在try/finally块中。此外,您将dispose放在了错误的位置,它需要在两行thumboil=bmp.Clone
之后进行处理。最后,您从未处理过thumboil
。我发布了一个答案,显示了正确的处理方法。您当前的方法中有一些主要的错误,您无法立即看到,但可能会出错我们的程序在运行数小时后随机崩溃。是的,我将对方法中的所有位图使用>使用块。对于>克隆行,不再需要>bmp位图。