Delphi 7,字符串问题

4
在我的项目中,我遇到了与字符串“内存溢出异常”相关的问题,没有使用MM。当字符串长度达到230万字符时,该问题就会出现。尽管有足够的内存,在代码的同一部分,我可以创建一个包含1亿个字符的字符串。
谷歌并没有帮助我解决这个问题,我也不能对其进行分解(因为我没有相关技能),所以我决定创建一个最小化测试示例,以便在少于20亿个字符的字符串上获取内存溢出异常。然而,我无法创建这样的示例,但我创建了一些更奇怪的东西:
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次迭代中只赋值一次,它不应该放慢速度。
问题:
  1. Delphi中的默认字符串是如何工作的?
  2. 如何避免减速?
  3. 如何避免内存溢出?
附言:如果将FastMM包含到主项目中,错误会消失。 P.S.取消对字符串的注释,我的Windows 7用户模式就会在3分钟内蓝屏。
2个回答

9
通过以下方式分配字符串
s := s + '{' +  b + '}';

在一个长时间运行的循环中,简单地分割您的内存。您可能拥有足够的内存来存储字符串,但这还不够。您需要连续的内存,但是您的分配模式会使这很困难。
通过调用SetLength将字符串预先分配到其最终所需的长度来解决问题。

4

1. Delphi中默认字符串是如何工作的?

每次通过:=赋值时都会分配一个新的string

也就是说,

s := s + '{' +  b + '}';

将为s+‘{’ + b + ‘}’分配一个string,然后将其复制到变量s中。

每次运行此行代码时,都会进行一次内存分配和一次内存释放。即使使用FastMM4,这也可能会很慢。但是对于旧的内存管理器来说,它可能会非常缓慢

2.如何避免减速?

如果您使用旧版Delphi并且使用“Borland”内存管理器,则分配和重新分配非常缓慢。而且它还会大量碎片化内存。

ss[1] := 'd'由于内存碎片化和Borland内存管理器必须为此行的内存分配进行一些缓慢的清理,因此肯定会非常缓慢。

请使用以下代码替换该行:

var ss: string[1];

它不再会变慢,因为shortstring将被分配到堆栈上,而堆不会被使用。

因此,为了避免减速:

  • 使用现代内存管理器,如FastMM4
  • 使用类似TStringBuilder的类或好用的老朋友TMemoryStream来追加数据:这样就会有更少的内存重分配,所以速度会快得多

3. 如何避免内存不足?

内存不足的错误来自于内存碎片化。

因此,前面问题中的两个解决方案将解决这个问题。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接