2017-02-01 14 views
2

32ビット版8GBメモリを搭載したWin 10システムでコンパイルする。 Tstringlist.Loadfromfileを使用して150MBのASCIIファイルをロードしようとなぜTstringlist.LoadFromfileはかなりのサイズのファイルをロードできませんか?

1200Mbをレポートタスクマネージャで「メモリ不足エラー」に使用できます。でも、ユニコードの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. 

要求されたとして、以下のファイルからいくつかのrepresentitiveテキストが....

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 

メモ帳++ 27万行を持つものとして、ファイルを報告します。

+1

32ビットプロセスで8GBでシステムがどのような処理を行うのか自分自身に問い合せてください。それは2GBだけアドレスすることができます。 PEオプションでLARGEADDRESSAWAREを有効にすると、4GBのアドレス空間が得られます。このようなファイルを読み込むための簡単なプログラムが成功するため、目に会うよりもこれ以上のことがあると私は思っています。 –

+5

私の見解では、GUIコントロールにこれを実際にロードしようとしている可能性があります。 190MBのテキストファイルを文字列リストに読み込むのに問題はありません。実際には、そのファイルを3つの異なるインスタンスに同時に読み込むことができます(同時にすべてのメモリに)。 4つ目の場合にのみ、メモリ不足のエラーが発生します。ですから、私はあなたが再生を提供するのをより困難に働き、少し戦闘的であることをお勧めします。 –

+0

完全なユニットを表示するようにコードを更新しました。私は新しいvclプロジェクトを作成し、ボタンとオープンダイアログを追加してファイルをロードしました。 –

答えて

4

各文字列は別々のヒープ割り当てが必要です。各ヒープ割り当ては、メモリのブロックを生成するが、メモリマネージャによって使用されるいくつかのメタデータも生成する。さらに、文字列には独自のメタデータ、参照カウント、および長さがあります。

あなたのファイルが非常に短い線の多くが含まれている場合は、メタデータを簡単に支配することができます。極端な場合、単一の文字列は20バイト以上を簡単に消費する可能性があります。私の頭の上から、私は実際のオーバーヘッドの数字を知らないので、これは推測です。非常に短い線で

は、文字列がたくさんあるでしょう。文字列リストが所有するポインタの配列自体は非常に大きくなる可能性があります。また、メモリのサイズを変更して割り当てを行うと、断片化が発生する可能性があります。あなたは2700万行があると言います。 1行に2つのポインタがあり、文字列とその関連オブジェクトはそれぞれ200MB以上です。すべてTStringList

すべてはあなたの仕事のための間違ったタイプです。文字列リーダーオブジェクトを使用して、行単位でファイルを読み込むことをお勧めします。テキストエディタのように、ファイル全体をメモリにロードし、専用の型を使用して行をオフセットにマップすることもできます。実際、テキストエディタは通常、アドレス空間の危機を避けるためにメモリマッピングを使用します。ファイルを使って何をしたいのか分からずに、推薦をするのは難しいですが、あなたの現在のアプローチに未来がない理由を理解するのを助けてくれることを願っています。

+0

これは正しいものでなければならないと思いますが、データを表現するためのサイズの10倍の増加は、どの標準でもひどく非効率的であり、デザインで標準として記述した方法を使用していたはずです。あなたが言っているのは、ストリングリストは絶対に避けなければならないということです。 –

+1

最近のバージョンのDelphiでは、各文字列に16バイトの接頭辞が付きます。 (古いバージョンは8だった)。 'TStringList'の各エントリは、StringListItemへのポインタ、文字列自体、および関連するオブジェクト(すなわち、+ 12バイト)を有する。したがって、文字列ごとに最低24バイトのオーバーヘッド。これは、FastMemのオーバーヘッドが小さなパディングを使用して断片化の一部を減らすことを前提としています(小さい割り当て範囲では平均5バイト未満ですが、それでも文字列あたりのオーバーヘッドです)。文字列ごとのオーバーヘッドは30バイトと見積もり、実際には保守的です。そしてそれは1.2ギガバイトの絶対最大値を30ミル線に制限するでしょう。 –

+1

あなたのニーズにちょうど間違ったタイプです。 'TStringList'は、このような巨大なファイルではなく、より小さな文字列のリストを管理するためのものです。それはそれが設計されているもののためには大丈夫ですが、あなたが必要とするものではありません。 –

関連する問題