3

私は実験しmmapていて、次のサンプルコードが付属しています:

    int main() {

    int fd;
    char *filename = "/home/manu/file";
    struct stat statbuf;
    int i = 0;
    char c = *(filename);

    // Get file descriptor and file length
    fd = open(filename, O_RDONLY);
    if (fd == -1) {
        perror("fopen error");
    }
    if (fstat(fd, &statbuf) < 0) {
        perror("fstat error");
    }
    printf("File size is %ld\n", statbuf.st_size);

    // Map the file
    char* mmapA = (char*) mmap(NULL, statbuf.st_size, PROT_READ, MAP_PRIVATE,
            fd, 0);
    if (mmapA == MAP_FAILED) {
        perror("mmap error");
        return 1;
    }

    // Touch all the mapped pages
    while (i < statbuf.st_size) {
        c = mmapA[i];
        i++;
    }
    c++;

    // Close file descriptor
    if (close(fd) == -1) {
        perror("close");
        return 1;
    }

    //Unmap file
    munmap(mmapA, statbuf.st_size);

    return EXIT_SUCCESS;
}

ファイルサイズは 137948 バイト = 134,7 キロバイトです。プログラムのメモリを検査するために、主に RES 列と VIRT 列の top を使用しています。これらの値を 3 つの異なる場所で探しています。

  1. mmap電話の直前
  2. mmap電話の直後
  3. マップされたすべてのメモリを読み取って、ファイルをメイン メモリに効果的にロードした後 (ページ フォールト後)

top によって報告される値は次のとおりです。

  1. VIRT = 1828 RES = 244
  2. VIRT = 1964 RES = 248
  3. VIRT = 1964 RES = 508

1964 年 - 1828 年 = 136、キロバイト単位で推測すると、ファイルのサイズと完全に一致します。

しかし、508 - 248 = 260 の RES の違いが理解できません。仮想メモリ サイズとファイル サイズが異なるのはなぜですか?

4

1 に答える 1

2

1 つ確かなことは、実行中のアプリケーションだけでなく、システムの状態にも結果が左右されるということです。私のマシンでは、プログラムを実行した最初の 2 回で RES の増加は 136 kB でしたが、その後の実行ではまったく増加しませんでした。おそらく、OS は既にファイル全体をキャッシュに持っていたのでしょう。興味深いことに、値自体は実行間で大きく異なりました。最初の実行では、RES のジャンプは 344 kB から 480 kB でしたが、後の実行では常に 348 kB の RES 値がありました。SHR にも同様の変化がありました。最初は 136 kB 増加し、その後変化はありませんでした。

ddアプリを実行する前に、後でゼロでマップされたファイルを上書きすることで、元のケース (136 kB ジャンプ) を自由に強制することができました。

出力を調べましたpmapsが、どちらの場合もまったく同じで、 への呼び出し後も変化しませんでしたmmap()

ここでは特大の RES ジャンプを再現できませんが、できることは次のとおりです。バイナリが としてコンパイルされているとしますa.out。の直後に 10 秒間のスリープを挿入し、 のmmap()直前にさらに 10 秒間のスリープを挿入しmunmap()ます。これにより、興味深い情報をダンプする時間枠が得られます。/procどのファイルがメモリに常駐しているかを正確に読み取ります。これを行うには、ターミナルで 2 つのタブを 1 回の実行で開きます。

./a.out

そしてすぐに他のタブで:

for ((i=0;i<4;i++)); do cat /proc/$(ps -fe | egrep '[a]\.out' | awk '{print $2}')/smaps > smaps.$i; sleep 5; done

これにより、プログラムのマップ状態の 4 つのスナップショットが 4 つの個別のファイルに作成されます。連続して番号が付けられたスナップショットの 1 つの違いは、RES サイズの急増中にどのような変化があったかを示しているはずです。サンプル実行中の私のマシンでは、違いはスナップショット 1 と 2 の間であり、変更は [マップされたファイルの名前を変更したことに注意してください。ここでは重要ではありません]:

user@machine:~$ diff -u smaps.{1,2}
--- smaps.1     2012-04-19 00:01:46.000000000 +0200
+++ smaps.2     2012-04-19 00:01:51.000000000 +0200
@@ -84,13 +84,13 @@
 MMUPageSize:           4 kB
 b782f000-b7851000 r--p 00000000 08:05 429102     /tmp/tempfile
 Size:                136 kB
-Rss:                   0 kB
-Pss:                   0 kB
+Rss:                 136 kB
+Pss:                 136 kB
 Shared_Clean:          0 kB
 Shared_Dirty:          0 kB
-Private_Clean:         0 kB
+Private_Clean:       136 kB
 Private_Dirty:         0 kB
-Referenced:            0 kB
+Referenced:          136 kB
 Swap:                  0 kB
 KernelPageSize:        4 kB
 MMUPageSize:           4 kB

マップされたファイルは最初はまったく常駐しておらず、後で 136 kB が常駐します。

あなたのシステムでは、差分が RES の追加の変更のソースにつながるはずです - 値が変更された他のファイルの名前を見つけることができるはずですRss[heap]一部のエントリはファイルではありませんが、他のメモリ領域です。たとえば、やなどのマーカーが見つかる場合があります[stack]。これは、システムライブラリがロードされ、スタックの使用量が増加しているというnosの提案を証明または反証する必要もあります。

于 2012-04-18T22:16:35.723 に答える