我使用的是帶有Unicode字符串的Delphi 2009。編碼超大文件時如何解決此EOutOfMemory異常?
我試圖編碼非常大的文件,將其轉換爲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}
所以我的記憶被分配,但它墜毀試圖用零填充它。這對我沒有意義。就我而言,內存甚至不需要用零來填充 - 無論如何這可能是浪費時間的 - 因爲無論如何Encoding語句都將填充它。
我可以以某種方式防止德爾福做記憶填充嗎?
或者有沒有其他方法可以讓Delphi爲我成功分配這個內存?
我的真正目標是爲我的非常大的文件做這個Encoding語句,所以任何解決方案,這將是非常讚賞。
結論:請參閱我對答案的評論。
這是在調試彙編代碼時要小心的警告。確保你在所有的「RET」行中都被打破,因爲我錯過了FillChar例程中的一個,並錯誤地推斷FillChar導致了這個問題。感謝梅森,指出這一點。
我將不得不將輸入分解爲塊以處理非常大的文件。
很高興我能幫上忙。 :) – 2010-06-29 03:13:21