Linux環境でC ++のメモリマッピングを理解してください。

Linux環境でC ++のメモリマッピングを理解してください。

私の使命は、メモリマップを探索し、それを利用できることを確認することです。

私はこの概念とコーディング方法を理解しようとしています。以下のビデオとブログ投稿のコードを試しましたが、簡単に再現できるように、ここでも手順を繰り返します。 LinuxシステムでC ++(gccバージョン11.2.0)を使用しています。

https://www.youtube.com/watch?v=m7E9piHcfr4

https://bertvandenbroucke.netlify.app/2019/12/08/memory-mapping-files/

これは私のコードです write_mmap.cpp

#include <fcntl.h>
#include <sys/mman.h>
#include <stdio.h>
#include <iostream>

int main() {
  // reading
  int file_read = open("test.dat", O_RDONLY, 0);
  // writing
  int file_write = open("test.dat", O_CREAT | O_RDWR,
                      S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP);
  posix_fallocate(file_write, 0, 4096);

  char *buffer = reinterpret_cast<char*> (mmap(NULL, 4096, PROT_WRITE, MAP_SHARED, file_write, 0));

  for (int i = 0; i < 4096; i++) {
    // Change each upper-case A to lowercase in the file
    if (buffer[i] == 'A') {
      buffer[i] = 'a';
    }
  }
}

test.datこんな感じ

Name,marker1,marker2,marker3,marker4
barc1,AA,AB,BB,--
barc2,AB,AA,BB,--

コマンドを実行した後

g++ write_mmap.cpp
./a.out

見るとこんなにtest.dat変わったと思います。

Name,marker1,marker2,marker3,marker4
barc1,aa,aB,BB,--
barc2,aB,aa,BB,--

これが私が望むものです。ここで多くのことについてよくわかりません。まず、test.datメモリマッピングファイルですか?ディレクトリにいるときにlsファイルシステムに見えますが、仮想メモリのどこかにありますか?それでは、仮想メモリのどこに保存されているかを知る方法がありますか?

私が書いたときは元のテキストファイルでしたが、スクリプトが完了した後にバイナリファイルになったのはなぜですか?nano次にファイルを開くとき

Name,marker1,marker2,marker3,marker4
barc1,aa,aB,BB,--
barc2,aB,aa,BB,--
^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^

また、メモリマッピングについて明確にしたいと思います。

  1. このファイルは現在RAMにあります。そうですか?どのプログラム(言語に関係なく)がメモリのこれらの部分を読み取ることができますか?

  2. このファイルに「ブックマーク」を設定する方法はありますか?もしそうなら、コンピュータが特定のセクションからファイルを読み始めるようにするには、アドレスAからアドレスBに読み込むように指示できますか?

ベストアンサー1

このファイルは現在RAMにあります。そうですか?

いいえ、ファイルはRAMにありません。ファイルの一部はRAMにあります。 2番目のパラメータは、mmapファイルマッピングに使用されるメモリセグメントのサイズを要求します。最後のパラメータはmmapファイル内の場所です。したがって、あなたの例では、ファイルの先頭から4Kbをマッピングします。ソースファイルのサイズが4097バイトの場合、最後のバイトはマッピングされません。mremapファイル内の他のチャンクに移動できます。

メモリがどこにあるのかを知りたい場合は、その戻りを見てくださいmmap。変数は、buffer正確にファイルがマップされたプロセスメモリの場所を指すポインタです。

どのプログラム(言語に関係なく)がメモリのこれらの部分を読み取ることができますか?

はい。しかし、少し複雑です。

mmapまず、thenを実行すると、fork子はポインタを継承し、まったく同じメモリにアクセスできます。

第二に、異なるプロセス(言語に関係なく)が同じファイルとファイル内の同じブロックをマッピングすることを決定した場合、同じメモリにアクセスできますが、そのプロセスのアドレス空間にマッピングされます。つまり、両方のプロセスがまだファイルの内容を配置して戦うことができますが、同じバイトを指すポインタは数値的に異なります。

サイズとオフセットを混在させることを忘れないでください。最初のアプリケーションは、オフセット0から4Kbファイルをマッピングします。他のアプリケーションは、オフセット1024において同じファイルの1Kbをマッピングする。したがって、1 つの 1Kb ブロックのみが競合の対象となります。この混合は非常に複雑な場合があります。この問題を解決するために(またはメモリ管理をより簡単にするために)「ページ」があります。これは、オフセットがページサイズの倍数でなければならないという要件によるものです。

このファイルに「ブックマーク」を設定する方法はありますか?もしそうなら、コンピュータが特定のセクションからファイルを読み始めるようにするには、アドレスAからアドレスBに読み込むように指示できますか?

いいえ、ブックマークはありません。ただし、6番目と2番目のパラメータはmmapこれを効果的に実行できます。最後のパラメータとアドレスです。第二最後の+ 2番目のパラメータですmmap

ところで、読み取るためにファイルを開く必要はありません。この場合は重複します。これで、同じファイルを指す2つのファイル記述子がありますが、読み取り専用ファイル記述子を無視しています。犯罪ではありませんが、潜在的なメモリリークの可能性があります。

^@これはファイルを開くときに見ることができるnano多くの内容ですposix_fallocate。この関数はファイルサイズが正しいことを確認しますmmap。技術的には、posix_fallocateファイルが要求されたセグメントを埋めるのに十分な大きさであれば、呼び出す必要はありませんmmap。ただし、ファイルが小さすぎる場合はposix_fallocate拡大してください。そのため、最初に前のデータが入力され、最後に0(^@- in 0 bytes nano)で埋められた4Kbファイルが作成されました。

おすすめ記事