私の使命は、メモリマップを探索し、それを利用できることを確認することです。
私はこの概念とコーディング方法を理解しようとしています。以下のビデオとブログ投稿のコードを試しましたが、簡単に再現できるように、ここでも手順を繰り返します。 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,--
^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^
また、メモリマッピングについて明確にしたいと思います。
このファイルは現在RAMにあります。そうですか?どのプログラム(言語に関係なく)がメモリのこれらの部分を読み取ることができますか?
このファイルに「ブックマーク」を設定する方法はありますか?もしそうなら、コンピュータが特定のセクションからファイルを読み始めるようにするには、アドレス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ファイルが作成されました。