私はacパーサーに取り組んでいますが、専門家が大量のテキスト/文字列(> 100MB)をメモリに保存する方法を知りたいですか?コンテンツは常に速いペースでアクセスできることが期待されます。bg: レッドハット/gcc/libc
単一の char 配列は境界外になり、セグメンテーション違反を引き起こします...任意のアイデアや経験を共有/議論することを歓迎します...
私はacパーサーに取り組んでいますが、専門家が大量のテキスト/文字列(> 100MB)をメモリに保存する方法を知りたいですか?コンテンツは常に速いペースでアクセスできることが期待されます。bg: レッドハット/gcc/libc
単一の char 配列は境界外になり、セグメンテーション違反を引き起こします...任意のアイデアや経験を共有/議論することを歓迎します...
VM 内のファイルを mmap(2) し、それをそのまま使用します。
「単一の文字配列が境界外になり、セグメンテーション違反が発生する」-これは正しくないと思います。セグメンテーション違反は、大きすぎるチャンクの割り当てではなく、保護されたメモリへのアクセスによって発生します。いずれにせよ、32 ビット マシンでは最大 2 ~ 3 GB、64 ビットではそれ以上を割り当てることができるはずです。
char 配列を使用できますが、高速アクセスが必要な場合は、その上に何らかのインデックスが必要になる可能性があります。
ユースケースをもっと明確にできますか? C 言語用のパーサーを作成しようとしていますか? なぜそんなに長い入力または出力が必要なのですか? ソースもバイナリも、一般的にはそれほど大きくありません。
mmap
そのデータへのランダムアクセスが必要な場合、ファイルに保存されている大量のデータを処理する最良の方法です。
mmap
アドレス空間の連続した部分をマップして、ファイルで見つかったデータを格納するように仮想メモリ システムに指示します。仮想メモリ システムは、そのファイルに基づいてアドレス空間の範囲を割り当てます。そのアドレス空間の任意の場所にアクセスすると、物理メモリのページが割り当てられ、ファイルのそのセクションがディスクから読み取られ、仮想アドレス空間のその部分がファイルの読み取りに使用された物理メモリにポイントされます。 . 物理メモリにより多くのスペースを確保する必要がある場合、ディスクに変更を書き込み (該当する場合)、仮想アドレス空間のそのセクションのマッピングを削除します。
次のように使用します。
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/mman.h> /* the header where mmap is defined */
#include <fcntl.h>
int file;
char *contents;
struct stat statbuf;
off_t len;
file = open("path/to/file", O_RDONLY);
if (file < 0)
exit(1); /* or otherwise handle the error */
if (fstat(file, &statbuf) < 0)
exit(1);
len = statbuf.st_size;
contents = mmap(0, len, PROT_READ, MAP_SHARED, file, 0);
if (contents == MAP_FAILED)
exit(1);
// Now you can use contents as a pointer to the contents of the file
// When you're done, unmap and close the file.
munmap(contents, len);
close(file);
これは非常に珍しいCパーサーであり、ソーステキスト(それがあなたが話しているものである場合)をメモリに保持する必要があります。ほとんどのパーサーは、ソースを一度に効果的にトークンを読み取り、それをすぐに内部表現に変換します。そして、それらは通常、単一のソースファイル(および#includes)の表現のみを保持します。これは、100Mbほどの大きさになる可能性はほとんどありません。おそらく、ここでいくつかの設計上の問題がありますか?
このような大量のデータは、次のように保存することをお勧めします
ただし、スタックに格納しないように注意してください。オーバーフローして他の問題が発生する可能性があります。
このデータを保存/アクセスするために効率的に使用できる特定のデータ構造について質問している場合は、次のことをお勧めします。
スタックに100Mb を超えるchar
配列を割り当てると、スタックがオーバーフローする可能性が高くなります。コンパイラ/リンカー オプションを使用してスタック サイズを増やすことはできますが、一部の OS はスタック ページ (Google の「スタック ガード ページ」) へのほぼ線形のアクセスを想定しているため、必ずしも問題が解決するとは限りません。
代わりに、コンパイル時にサイズがわかっている場合は、static char
代わりに配列を割り当ててみてください。いっそのこと、使用しますmalloc()
。(投稿したコードは、サイズが変数に依存する配列を宣言します。a
これは「可変長配列」と呼ばれ、すべてのコンパイラがサポートしているわけではない C99 拡張機能です。OTOH のすべての C 実装ではmalloc()
、メモリを動的に割り当てるために呼び出すことができます。 )
ソースストリーム(おそらくテキストファイル)からトークンを読み取るときにトークンを圧縮することで、多くのスペースを節約できます。入力テキストを読むときに余分な空白やコメントを削除すると、メモリ要件を最大50%削減できます。
しかし、なぜ一度にたくさんのメモリを保存する必要があるのか興味があります。文字列リテラル、識別子、およびシンボルテーブルのエントリは、解析中にアクセスできなくなったり、スコープ外になったりしたときに、ディスクにキャッシュできます。
pbm初心者でしたら申し訳ありませんが、セグメンテーション違反は以下のように表示されます。
int a = 10000000;
char content2[a];
content2[0] = 'a';
ユースケースは、ファイルは非常に静的なデータ自体を解析する前に(xmlと同様に)構造的なプレーンテキスト形式で毎日生成されることです。できるだけ早くアクセスできるようにしたいので、それを保持することを好みます解析後のメモリ内