Wikipediaによると(間違っている可能性があります)
fork()システムコールが実行されると、親プロセスに対応するすべてのページのコピーが作成され、オペレーティングシステムによって子プロセスの別々のメモリ位置にロードされます。しかし、場合によってはこれは必要ありません。子プロセスは "
exec
"システムコール(Cプログラムで実行可能ファイルを実行するために使用されます)を実行するか、またはfork()
。exec
これは、実行されるコマンドがそれを呼び出したプロセスのアドレス空間を置き換えるためです。この場合、COW(記録中のコピー)という技術が使用されます。この手法では、フォークが発生したときに親プロセスのページが子プロセスにコピーされません。代わりに、子プロセスと親プロセスの間でページが共有されます。プロセス(親または子)がページを変更するたびに、変更を実行したプロセス(親または子)に対して、特定のページの別々のコピーが別々に作成されます。その後、このプロセスは将来のすべての参照で共有ページの代わりに新しくコピーされたページを使用します。他のプロセス(共有ページを変更していないプロセス)は、ページの元のコピー(これ以上共有されていない)を引き続き使用します。プロセスがページに書き込まれるとページがコピーされるため、この手法は記録中のコピーと呼ばれます。
いずれかのプロセスがページに書き込もうとすると、ページの新しいコピーが割り当てられ、ページエラーを生成したプロセスに提供されるように見えます。これにより、元のページが書き込み可能としてマークされます。
私の質問は:fork()
プロセスが共有ページに書き込もうとする前に何度も呼び出されるとどうなりますか?
答え1
特別なことは起こりません。すべてのプロセスは同じページセットを共有し、各プロセスはページを変更しようとすると独自のプライベートコピーを取得します。
答え2
fork() の動作は *nix システムに MMU があるかどうかによって異なります。 MMU以外のシステム(初期PDP-11など)では、fork()システムコールは各子プロセスのすべての親プロセスのメモリをコピーします。 MMUベースの* nixシステムでは、カーネルはスタック以外のすべてのページをR / Oとしてマークし、それらを親と子の間で共有します。その後、2つのプロセスのいずれかがページに書き込まれると、MMUはその試みをキャプチャし、カーネルは書き込み可能ページを割り当て、現在書き込み可能ページを指すようにMMUページテーブルを更新します。この書き込み中のコピー動作は、最初に各サブプロセスに専用スタックを割り当てて複製するだけで速度が向上します。
各fork()呼び出しの間にいくつかの親コードを実行すると、結果の子プロセスは親プロセスによって変更されたページによって異なります。一方、親プロセスが複数のfork()呼び出し(ループなど)を実行している場合、子プロセスはほぼ同じです。ローカルループ変数を使用する場合、各サブスタックの変数は異なります。
答え3
システムがフォークを実行すると、通常(実装によって異なります)、ページは読み取り専用としてマークされ、親プロセスはそのページのデフォルトプロセスとして表示されます。
これらのページに書き込もうとすると、ページエラーが発生し、オペレーティングシステムが代わりにページの全リストをコピーするか、変更されたページのみがコピーされる(実装によって異なります)、書き込みプロセスで書き込み可能なコピーがあります。
同じプロセスで複数のプロセスが分岐している場合、「デフォルト」プロセスがメモリに書き込むとき、その他プロセスはそのページをコピーします。