3

私のプログラムは C で書かれており、gcc でコンパイルしています。ファイルを読み込んで、ファイルの内容をバッファに保存しています。そのためには、バッファーをファイルと同じ大きさにする必要があります。私は malloc() を使用してバッファにメモリを割り当てています。残念ながら、277MB のファイルに出くわしました。それはヒープには多すぎますか?実行時にセグ フォールトが発生しますが、それ以上の情報はありません。160 MB もの大きなファイルでも機能しますが、277 MB ファイルのこの 1 つの外れ値がそれを破っています。

編集:valgrindは私に与えます

@ 0xC0000022L valgrind がくれた

==6380== Warning: set address range perms: large range [0x8851028, 0x190e6102) (undefined)
==6380== Warning: set address range perms: large range [0x8851028, 0x190e6028) (defined)
==6380== Warning: set address range perms: large range [0x190e7028, 0x2997c108) (undefined)
==6380== Warning: set address range perms: large range [0x190e7028, 0x2997c028) (defined)
==6380== Warning: silly arg (-1737565464) to malloc()
==6380== Invalid write of size 4
==6380==    at 0x8048A49: main (newanalyze.c:85)
==6380==  Address 0x4a00 is not stack'd, malloc'd or (recently) free'd
==6380==
==6380==
==6380== Process terminating with default action of signal 11 (SIGSEGV)
==6380==  Access not within mapped region at address 0x4A00
==6380==    at 0x8048A49: main (newanalyze.c:85)

しかし、85 行目は、ファイルのサイズの影響を受けない小さな変数です。

4

3 に答える 3

4

Valgrind からの出力に注意してください。

==6380== 警告: ばかげた引数 (-1737565464) を malloc() に

-1737565464 は signed int 値ですが、unsigned int として取得すると 2557401832 (>2G) になります。277M の代わりに >2G パラメータを malloc に渡しています。

また、次の情報から、無効なアドレスであるアドレス 0x4a00 に書き込もうとしていることがわかります。このシナリオでは SEGV が予想されます。コード内の newanalyze.c:85 をチェックして、そこにあるものを確認してください。

==6380== サイズ 4 の無効な書き込み

==6380== at 0x8048A49: メイン (newanalyze.c:85)

==6380== アドレス 0x4a00 は、スタック、malloc、または (最近) 解放されていません

于 2012-07-12T17:19:14.047 に答える
1

コメントの 1 つに続いて、 mmap(2)を使用してファイルを開く方法を次に示します。これは、UNIX を使用していると仮定しています。

int fd;
struct stat S;
const char* file_base;

if ((fd = open(filename, O_RDONLY)) < 0) {
    fprintf(stderr, "Can't open file %s to read\n", filename);
    return NULL;
}
if (fstat(fd, &S) != 0) {
    fprintf(stderr, "Can't stat file %s!\n", filename);
    close(fd);
    return NULL;
}
if ((file_base = mmap(NULL, S.st_size, PROT_READ, MAP_FILE|MAP_PRIVATE, fd, 0)) == MAP_FAILED) {
    fprintf(stderr, "Unable to map file %s\n", filename);
    close(fd);
    return NULL;
}

この後file_base、ファイルの内容全体を含むメモリのビットを指します。

この方法の利点は次のとおりです。

  • 基本的にメモリを消費しません(一種)。ここで実際に起こっていることは、ファイルを少しのメモリのスワップ スペースにしていることです。
  • 時間はかかりません(一種)。新しく識別されたメモリのビットはスワップアウトされた状態で開始されるため、メモリがアクセスされると、ファイルのそのビットがスワップインされるだけで済みます。これは、mallocで動的に割り当てられた場合と同じくらい迅速に行われます。 (3) .

これには、読み取り専用とマークされたメモリのビットがあります。このトリックはファイルの読み書きでも実行できますが、メモリに書き込むと同時にファイルが変更されることになります。

Unix を使用していない場合でも、mmap使用できる機能がまだある可能性があります。そうでない場合は、同じことを行う Windows ネイティブの方法がいくつかあります ( CreateFileMapping)。

于 2012-07-12T14:35:20.460 に答える
0

残念ながら、確かな「理由」をお伝えすることはできませんが、システムで malloc が呼び出しているように見える mmap2 は、単にメモリ不足であると報告しています。この場合、malloc は NULL を返し、segfault を引き起こします。

munmap(0xb7706000, 4096)                = 0
mmap2(NULL, 2557403136, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = -1  ENOMEM (Cannot allocate memory)

反例として、次のように成功するおもちゃのプログラムがあります。

mmap(NULL, 283652096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f2d00994000

システムで使用可能なメモリ、またはプログラムが使用しているメモリを確認します。ひどくメモリリークしているのかもしれませんか?

于 2012-07-12T14:28:31.807 に答える