Delphi &引用;“存储空间不足”;使用位图时出错
当我尝试设置BMP.Height或BMP.Width时,当我尝试使用BMP文件时,我得到一个“OutofResources-没有足够的存储空间”。i在这些指令之后,堆栈跟踪立即为(按此顺序): ntdll.dll.RtlLeaveCriticalSection、kernel32.dll.FileTimeToDosDateTime、GDI32.dll.GdiReleaseDC、GDI32.dll.PatBlt、kernel32.dll.ReadFile或类似文件:Delphi &引用;“存储空间不足”;使用位图时出错,delphi,Delphi,当我尝试设置BMP.Height或BMP.Width时,当我尝试使用BMP文件时,我得到一个“OutofResources-没有足够的存储空间”。i在这些指令之后,堆栈跟踪立即为(按此顺序): ntdll.dll.RtlLeaveCriticalSection、kernel32.dll.FileTimeToDosDateTime、GDI32.dll.GdiReleaseDC、GDI32.dll.PatBlt、kernel32.dll.ReadFile或类似文件: |7E429130|user32
|7E429130|user32.dll GetParent
|7C90FF2D|ntdll.dll RtlGetNtGlobalFlags
|77F15A00|GDI32.dll GdiReleaseDC
|7C83069E|kernel32.dll FileTimeToDosDateTime
|7C9010E0|ntdll.dll RtlLeaveCriticalSection
| |my function (where I set BMP.Height or BMP.Width)
当时我确信这与内存碎片有关——系统有足够的空闲ram来处理我的图像,但内存是碎片化的,因此没有足够大的块来保存我的图像。但我也看到过它在Windows启动11秒后发生过一次。我的程序在循环中循环,我只处理一次图像!因此,这与RAM碎片无关
当我得到这个错误时,不同的情况(但仍然与绘图有关)如下:
|77F16A7E|GDI32.dll IntersectClipRect
|77F16FE5|GDI32.dll BitBlt
|7E429011|user32.dll OffsetRect
|7E42A97D|user32.dll CallWindowProcA
|7E42A993|user32.dll CallWindowProcA
|7C9010E0|ntdll.dll RtlLeaveCriticalSection
|7E4196C2|user32.dll DispatchMessageA
|7E4196B8|user32.dll DispatchMessageA
|0058A2E1|UTest.exe UTest.dpr
|7C90DCB8|ntdll.dll ZwSetInformationThread
我认为在BMP.Height之后的堆栈跟踪中总是有一个“RtlLeaveCriticalSection”调用
有帖子指出了通过编辑Windows注册表项可能的解决方案。然而,邮报说它只适用于赢得XP。而我的错误也出现在Win7上
我看到许多类似的帖子(其中一些与将文件保存到磁盘有密切关系),但直到没有人回来报告他修复了错误
更新: 根据您的要求,这是出现错误的代码:
procedure TMyBitmap.SetLargeSize(iWidth, iHeight: Integer);
CONST ctBytesPerPixel= 3;
begin
{ Protect agains huge/empty images }
if iWidth< 1 then iWidth:= 1 else
if iWidth> 32768 then iWidth:= 32768;
if iHeight< 1 then iHeight:= 1 else
if iHeight> 32768 then iHeight:= 32768;
{ Set image type }
if iWidth * iHeight * ctBytesPerPixel > 9000000 {~9MB}
then HandleType:= bmDIB { Pros and cons: -no hardware acceleration, +supports larger images }
else HandleType:= bmDDB;
{ Total size is higher than 1GB? }
if (iWidth* iHeight* ctBytesPerPixel) > 1*GB then
begin
Width := 8000; { Set a smaller size }
Height := 8000; { And rise an error }
RAISE Exception.Create('Image is too large.');
end;
{ Set size }
Width := iWidth; <----------------- HERE
Height:= iHeight;
end;
过程TMyBitmap.SetLargeSize(iWidth,iHeight:Integer);
常数ctbytesperpoixel=3;
开始
{保护大/空图像}
如果iWidth<1,则iWidth:=1
如果iWidth>32768,则iWidth:=32768;
如果iHeight<1,则iHeight:=1,否则
如果iHeight>32768,则iHeight:=32768;
{设置图像类型}
如果iWidth*iHeight*ctBytesPerPixel>9000000{~9MB}
然后HandleType:=bmDIB{优点和缺点:-无硬件加速,+支持更大的图像}
else HandleType:=bmDDB;
{总大小大于1GB?}
如果(iWidth*iHeight*ctbytesperpoixel)>1*GB,则
开始
宽度:=8000;{设置较小的大小}
高度:=8000;{并引发错误}
引发异常。创建('图像太大');
结束;
{设置大小}
宽度:=宽度 根据我的实验,最大位图大小取决于:
- 操作系统版本(例如XP似乎允许比七个更小的位图资源)李>
- 操作系统版本(64位操作系统允许比32位操作系统更大的资源分配)李>
- 当前安装的RAM(和免费的)李>
- 已分配的位图数(因为它们是共享资源)
因此,当您开始处理大数据(比屏幕上的位图分辨率更高)时,您无法确定位图分配是否成功
以下是一些潜在的解决方案(我已经使用了其中的一些):
- 不要分配位图资源,而是分配一个普通内存块,然后使用直接Win32 BitBlt API绘制它-但您必须编写一些专用的进程函数(或使用一些第三方库),在32位操作系统上,IMHO VirtualAlloc API(FastMM4为大内存块调用的API)无法分配超过1 GB的连续内存李>
- 以前版本的增强:要么使用64位进程来处理巨大的RAM块(欢迎使用XE2编译器),要么使用文件作为临时存储,然后内存映射其内容以进行处理(这是PhotoShop或其他处理巨大内存的方式)-如果您有足够的RAM,则不需要使用临时文件(磁盘上不会写入任何数据)
- 将大图片平铺成小图片-JPEG库只能渲染图片的一部分,并且可以轻松地放入位图资源中
- 在所有情况下,防止任何重复的位图资源(因为所有位图资源都是共享的):例如,如果您正在读取位图,请将其内容复制到临时内存块或文件中,释放其资源,然后分配目标位图
- 关于性能,先做对,然后再做快——不要过早地在实现中包含“技巧”(您的客户可能会接受等待几秒钟,但不会接受全局失败)
没有完美的解决方案(我的首选是使用较小的图片,因为它具有易于多线程处理的优点,因此使用新的CPU可能会加快很多速度),请注意,资源分配可能在您全新的64位Windows 7 PC上工作,但在您客户的32位XP计算机上失败。请显示源代码…听起来更像是资源泄漏(即句柄泄漏)而不是内存问题…位图有多大?位图可以有任何大小。通常它们应该是普通数码相机图片(4-16 MPixel)。更新:这家伙说他有一个解决方案,将格式设置为PF24位:将图像合并,不要不断创建/销毁。