gpt4 book ai didi

delphi - 编码非常大的文件时如何解决此 EOutOfMemory 异常?

转载 作者:行者123 更新时间:2023-12-03 15:18:06 25 4
gpt4 key购买 nike

我正在使用带有 Unicode 字符串的 Delphi 2009。

我正在尝试对一个非常大的文件进行编码以将其转换为 Unicode:

var
Buffer: TBytes;
Value: string;

Value := Encoding.GetString(Buffer);

这对于 40 MB 的缓冲区来说效果很好,缓冲区大小加倍,并以 80 MB Unicode 字符串的形式返回值。

当我使用 300 MB 缓冲区尝试此操作时,它给出了 EOutOfMemory 异常。

嗯,这并不完全出乎意料。但我还是决定追查到底。

它进入系统单元中的 DynArraySetLength 过程。在该过程中,它进入堆并调用 ReallocMem。令我惊讶的是,它成功分配了 665,124,864 字节!!!

但在 DynArraySetLength 结束时,它调用 FillChar:

  // Set the new memory to all zero bits
FillChar((PAnsiChar(p) + elSize * oldLength)^, elSize * (newLength - oldLength), 0);

你可以通过评论看到它应该做什么。该例程没有太多内容,但它是导致 EOutOfMemory 异常的例程。这是来自系统单元的 FillChar:

procedure _FillChar(var Dest; count: Integer; Value: Char);
{$IFDEF PUREPASCAL}
var
I: Integer;
P: PAnsiChar;
begin
P := PAnsiChar(@Dest);
for I := count-1 downto 0 do
P[I] := Value;
end;
{$ELSE}
asm // Size = 153 Bytes
CMP EDX, 32
MOV CH, CL // Copy Value into both Bytes of CX
JL @@Small
MOV [EAX ], CX // Fill First 8 Bytes
MOV [EAX+2], CX
MOV [EAX+4], CX
MOV [EAX+6], CX
SUB EDX, 16
FLD QWORD PTR [EAX]
FST QWORD PTR [EAX+EDX] // Fill Last 16 Bytes
FST QWORD PTR [EAX+EDX+8]
MOV ECX, EAX
AND ECX, 7 // 8-Byte Align Writes
SUB ECX, 8
SUB EAX, ECX
ADD EDX, ECX
ADD EAX, EDX
NEG EDX
@@Loop:
FST QWORD PTR [EAX+EDX] // Fill 16 Bytes per Loop
FST QWORD PTR [EAX+EDX+8]
ADD EDX, 16
JL @@Loop
FFREE ST(0)
FINCSTP
RET
NOP
NOP
NOP
@@Small:
TEST EDX, EDX
JLE @@Done
MOV [EAX+EDX-1], CL // Fill Last Byte
AND EDX, -2 // No. of Words to Fill
NEG EDX
LEA EDX, [@@SmallFill + 60 + EDX * 2]
JMP EDX
NOP // Align Jump Destinations
NOP
@@SmallFill:
MOV [EAX+28], CX
MOV [EAX+26], CX
MOV [EAX+24], CX
MOV [EAX+22], CX
MOV [EAX+20], CX
MOV [EAX+18], CX
MOV [EAX+16], CX
MOV [EAX+14], CX
MOV [EAX+12], CX
MOV [EAX+10], CX
MOV [EAX+ 8], CX
MOV [EAX+ 6], CX
MOV [EAX+ 4], CX
MOV [EAX+ 2], CX
MOV [EAX ], CX
RET // DO NOT REMOVE - This is for Alignment
@@Done:
end;
{$ENDIF}

所以我的内存已分配,但在尝试用零填充时崩溃了。这对我来说没有意义。就我而言,内存甚至不需要用零填充 - 无论如何这可能是浪费时间 - 因为编码语句无论如何都会填充它。

我可以以某种方式阻止 Delphi 进行内存填充吗?

或者有其他方法可以让 Delphi 为我成功分配此内存吗?

我的真正目标是为我的非常大的文件执行该编码语句,因此任何允许这样做的解决方案将不胜感激。

<小时/>

结论:请参阅我对答案的评论。

这是在调试汇编代码时要小心的警告。确保在所有“RET”行上中断,因为我错过了 FillChar 例程中间的一行,并错误地得出结论是 FillChar 导致了问题。感谢梅森指出了这一点。

我必须将输入分解为 block 才能处理非常大的文件。

最佳答案

FillChar 没有分配任何内存,所以这不是你的问题。尝试跟踪它并在 RET 语句处放置断点,您将看到 FillChar 完成。无论问题是什么,都可能在稍后的步骤中出现。

关于delphi - 编码非常大的文件时如何解决此 EOutOfMemory 异常?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3137427/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com