サイズが 24 MB (1 行あたり平均 17 文字) の 140 万行の大きなテキスト ファイルを読み込んでいます。
私は Delphi 2009 を使用しており、ファイルは ANSI ですが、読み取り時に Unicode に変換されるため、変換後のテキストのサイズは 48 MB であると言えます。
(編集:もっと簡単な例を見つけました...)
このテキストを単純な StringList にロードしています。
AllLines := TStringList.Create; AllLines.LoadFromFile(Filename);
私は、データ行が 48 MB よりも多くのメモリを必要とするように見えることを発見しました。
実際、155 MB のメモリを使用しています。
Delphi が 48 MB または 60 MB を使用していても、メモリ管理のオーバーヘッドを考慮して問題ありません。しかし、155 MB は過剰に思えます。
これは StringList の障害ではありません。以前に行をレコード構造にロードしようとしましたが、同じ結果 (160 MB) が得られました。
Delphi または FastMM メモリ マネージャが、文字列を格納するために必要なメモリ量の 3 倍の量を使用する原因が何なのか、私にはわかりません。ヒープ割り当てはそれほど非効率的ではありませんよね?
私はこれをデバッグし、できる限り調査しました。なぜこれが起こっているのかについてのアイデア、または過剰な使用を減らすのに役立つアイデアは大歓迎です.
注: この「小さい」ファイルを例として使用しています。私は実際に 320 MB のファイルをロードしようとしていますが、Delphi は 2 GB を超える RAM を要求しており、この過剰な文字列要件のためにメモリが不足しています。
補遺: Marco Cantu が、Delphi と Unicode に関するホワイト ペーパーを発表しました。Delphi 2009 では、文字列あたりのオーバーヘッドが 8 バイトから 12 バイトに増加しました (さらに、文字列への実際のポインタの場合はさらに 4 バイト)。17x2 = 34 バイト ラインごとに 16 バイトが追加されると、ほぼ 50% が追加されます。しかし、オーバーヘッドが 200% を超えています。余分な 150% は何になるでしょうか?
成功!!皆様のご提案に感謝いたします。みなさん、考えさせられました。しかし、彼が尋ねたので、私は Jan Goyvaerts に答えを与えなければなりません:
...なぜ TStringList を使用しているのですか? ファイルは本当に別の行としてメモリに格納する必要がありますか?
その結果、24 MB のファイルを 140 万行の StringList としてロードする代わりに、プログラムが認識している自然なグループに行をグループ化できるという解決策にたどり着きました。そのため、127,000 行が文字列リストに読み込まれました。
現在、各行の平均文字数は 17 文字ではなく 190 文字です。StringList 行ごとのオーバーヘッドは同じですが、行数が大幅に少なくなりました。
これを 320 MB のファイルに適用すると、メモリが不足することはなくなり、1 GB 未満の RAM にロードされるようになりました。(そして、読み込みに約10秒しかかかりません。これはかなり良いです!)
グループ化された行を解析するために少し余分な処理が必要になりますが、各グループのリアルタイム処理では目立たないはずです。
(念のために言っておきますが、これは家系図プログラムであり、32 ビット アドレス空間に約 100 万人のすべてのデータを 30 秒以内にロードできるようにするために必要な最後のステップかもしれません。インデックスをデータに追加するための 20 秒のバッファがまだあります。これは、データの表示と編集を可能にするために必要です。)