在我的项目中,我遇到了字符串“内存不足异常”的问题,不使用MM。这个问题显示当字符串的长度达到23万个符号时。尽管有足够的内存,在代码的同一部分,我可以创建一个包含100,000,000个字符的线索。
谷歌没有帮助,我不能拆解它(没有技能),所以我决定创建一个最小的测试示例,在那里,我可以从内存异常中得到的字符串不到2000 000 000个符号。我不能创造这样的例子,但我创造了一些奇怪的东西:
program Project2;
{$APPTYPE CONSOLE}
uses
SysUtils;
var s : string;
k : integer;
function b : string;
begin
result := 'f';
end;
procedure c;
var ss : string;
begin
s := s + '{' + b + '}';
ss := 'a';
if k mod 100001 = 0 then
begin
// ss[1] := 'd'; // uncoment me
write(k mod 10);
end;
inc(k);
end;
begin
while true do c;
end.这个代码很好用。它只是在全局字符串中添加了一些额外的操作。问题是,如果您取消注释标记的字符串,它将显着地慢下来(不管有没有优化)。考虑到这个赋值值在100,001次迭代中一次,就不能慢下来。
问题:
如果我将FastMM包含到主项目中,错误就会消失,P.S。这个字符串未注释的示例在3分钟内(从用户模式)将我的Windows 7发送到BSOD。
发布于 2012-04-12 13:34:05
1. Delphi中的默认字符串是如何工作的?
每次(通过一个string )受影响时都会分配一个新的:=。
那是,
s := s + '{' + b + '}';将为string分配一个s + '{' + b + '}';,然后将其复制到变量s。
每次运行这一行时,都有一个内存分配和一个内存释放。即使使用FastMM4,这也可能是缓慢的。但是对于老的MM来说,它可能会非常慢。
2.如何避免减速?
如果您在旧的Delphi中,使用"Borland“内存管理器,分配和重新分配是非常缓慢的。它会破坏很多记忆。
由于内存碎片,以及Borland内存管理器必须对此行的内存分配进行一些缓慢清理,ss[1] := 'd'当然非常慢。
用以下方式更改行:
var ss: string[1];而且它不会再慢下来了,因为shortstring将在堆栈上分配,堆也不会被使用。
因此,为了避免减速:
TStringBuilder-like类,或者是一个很好的旧TMemoryStream,您可以在其中追加数据:您的内存重新分配会少得多,所以它会更快。3.如何避免内存不足?
内存不足的错误来自内存碎片。
因此,前一个问题的两个解决方案将解决这个问题。
发布于 2012-04-12 11:13:14
通过执行
s := s + '{' + b + '}';在一个长时间运行的循环中,您的内存只会被分割。您很可能有足够的内存来处理字符串,但这还不够。您需要内存是连续的,但是您的分配模式会使这很困难。
通过调用SetLength将字符串预先分配到其最终想要的长度来解决这个问题。
https://stackoverflow.com/questions/10122338
复制相似问题