为什么Tstringlist.LoadFromfile无法加载合理大小的文件?

时间:2017-02-01 10:27:59

标签: delphi delphi-10.1-berlin

在具有8位内存32位的Win 10系统上进行编译。

尝试使用Tstringlist.Loadfromfile加载150Mb的ASCII文件,出现“内存不足错误”,任务管理器报告使用1200Mb。

即使Unicode的50%冗余也无法解释这种低效率的水平!

有什么想法吗?

示例代码。

unit Unit3;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls;

type
  TForm3 = class(TForm)
    OpenDialog1: TOpenDialog;
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form3: TForm3;

implementation

{$R *.dfm}

procedure TForm3.Button1Click(Sender: TObject);
var f:tstringlist;
begin
  if opendialog1.Execute then
  begin
    f:=Tstringlist.create;
    try
      f.Loadfromfile(Opendialog1.Filename);
    finally
      f.free
    end
  end;
end;

end.

根据要求,以下文件中的一些代表性文字......

AcDbPolyline
 90
5
 70
0
 10
100091.01
 20
59019.75
 10
100077.39
 20
59001.49
 10
100070.7
 20
58974.72
 10
100066.85
 20
58942.73
 10
100065.12
 20
58920.69
  0
LWPOLYLINE
  5

Notepad ++报告该文件有2700万行。

1 个答案:

答案 0 :(得分:4)

每个字符串都需要单独的堆分配。每个堆分配产生一块内存,但也会产生内存管理器使用的一些元数据。最重要的是,字符串有自己的元数据,引用计数和长度。

如果您的文件包含很多非常短的行,那么元数据很容易占主导地位。在extremis中,单个字符串可能很容易消耗20个字节或更多。在我的头顶,我不知道实际的开销数字,所以这是一个猜测。

线条非常短,会有很多字符串。字符串列表拥有的指针数组本身可能非常大。如果通过调整内存大小分配可能会导致碎片。你说有2700万行。每行两个指针,一个是字符串,另一个是相关对象,单独超过200MB。

总而言之,TStringList是您的任务的错误类型。您最好用文件串阅读器对象逐行读取文件。或者将整个文件加载到内存中,并使用专用类型将行映射到偏移,就像文本编辑器一样。事实上,文本编辑器通常使用内存映射来避免地址空间危机。如果不知道你想对文件做什么,很难提出建议,但我希望我能帮助你理解为什么你现在的方法没有前途。