4

基本的にこれを行うプログラムがあります:

  1. バイナリファイルを開きます
  2. 4MB のチャンクを使用して、ファイルを逆方向​​に読み取ります(逆方向とは、EOF の近くで開始し、ファイルの先頭で読み取りを終了することを意味します。つまり、ファイルを「右から左」に読み取ります)。
  3. ファイルを閉じます

私の質問は、添付されたコードに明らかなメモリ リークがないにもかかわらず、メモリ消費量が以下のように見えるのはなぜですか?

プログラム実行時のメモリ消費量

上記の画像を取得するために実行されたプログラムのソースは次のとおりです。

#include <stdio.h>
#include <string.h>

int main(void)
{
    //allocate stuff
    const int bufferSize = 4*1024*1024;
    FILE *fileHandle = fopen("./input.txt", "rb");
    if (!fileHandle)
    {
        fprintf(stderr, "No file for you\n");
        return 1;
    }
    unsigned char *buffer = new unsigned char[bufferSize];
    if (!buffer)
    {
        fprintf(stderr, "No buffer for you\n");
        return 1;
    }

    //get file size. file can be BIG, hence the fseeko() and ftello()
    //instead of fseek() and ftell().
    fseeko(fileHandle, 0, SEEK_END);
    off_t totalSize = ftello(fileHandle);
    fseeko(fileHandle, 0, SEEK_SET);

    //read the file... in reverse order. This is important.
    for (off_t pos = totalSize - bufferSize, j = 0;
        pos >= 0;
        pos -= bufferSize, j ++)
    {
        if (j % 10 == 0)
        {
            fprintf(stderr,
                "reading like crazy: %lld / %lld\n",
                pos, totalSize);
        }

        /*
         * below is the heart of the problem. see notes below
         */
        //seek to desired position
        fseeko(fileHandle, pos, SEEK_SET);
        //read the chunk
        fread(buffer, sizeof(unsigned char), bufferSize, fileHandle);
    }

    fclose(fileHandle);
    delete []buffer;
}

また、次の観察結果があります。

  1. RAM の使用量は 1GB 増加しますが、プログラム全体が実行全体で 5MB しか使用しません。
  2. fread()outへの呼び出しをコメント化すると、メモリ リークがなくなります。これは奇妙です。メモリリークを引き起こす可能性のあるものを近くに割り当てていないためです...
  3. fseeko()また、逆方向 (= outへのコメント呼び出し) ではなく、通常どおりにファイルを読み取ると、メモリ リークもなくなります。これは超奇妙な部分です。

さらに詳しい情報...

  1. 以下は役に立ちません:
    1. -の結果を確認fread()しても、異常はありません。
    2. 通常、32 ビットfseek、およびftell.
    3. のようなことをしてsetbuf(fileHandle, NULL)います。
    4. のようなことをしてsetvbuf(fileHandle, NULL, _IONBF, *any integer*)います。
  2. Windows 7 で cygwin と mingw を使用して g++ 4.5.3 でコンパイル。最適化なしで、ただg++ test.cpp -o test. どちらもそのような動作を示します。
  3. テストで使用されたファイルは、長さが 4GB で、ゼロがいっぱいでした。
  4. グラフの中央にある奇妙な一時停止は、この質問とは関係なく、ある種の一時的な I/O ハングアップで説明できます。
  5. 最後に、読み取りを無限ループでラップすると、最初の反復後にメモリ使用量の増加が止まります。

ファイル全体でいっぱいになるまで、ある種の内部キャッシュが構築されていることに関係していると思います。舞台裏で実際にどのように機能していますか?ポータブルな方法でそれを防ぐにはどうすればよいですか??

4

2 に答える 2

2

Javaでもまったく同じ問題がありましたが、このコンテキストでは問題ありません。一度にはるかに大きなチャンクを読み取ることで解決しました。4Mb サイズのチャンクも読みましたが、それを 100 ~ 200Mb に増やしたところ、問題はなくなりました。おそらく、それはあなたのためにもそうするでしょう。私はWindows 7を使用しています。

于 2015-02-02T08:14:01.237 に答える