web-dev-qa-db-ja.com

Linuxでfork()はすぐにプロセスヒープ全体をコピーしますか?

fork()システムコール は、実行中のプロセスから子プロセスを複製します。 2つのプロセスは、PIDを除いて同じです。

当然、プロセスがヒープに書き込むのではなく、ヒープから読み取るだけの場合、ヒープをコピーすることはメモリの大きな浪費になります。

プロセスヒープ全体がコピーされますか?書き込みのみがヒープのコピーをトリガーするように最適化されていますか?

31
Adam Matan

fork()の-​​entiretyは、mmap/copy on writeを使用して実装されます。

これは、ヒープだけでなく、共有ライブラリ、スタック、BSS領域にも影響します。

つまり、結果として生じる2つのプロセス(親と子)が実際にメモリ範囲への書き込みを開始するまで、フォークは非常に軽量な操作です。この機能は、フォークボムの致命性の主な原因です。カーネルがページの複製と差別化で過負荷になる前に、プロセスが多すぎます。

カーネルがハードコピーを実行する操作の例(デバイスドライバーは例外です)を最新のOSで見つけるのは難しいでしょう-使用するのははるかに簡単で効率的ですVM機能性。

execve()でさえ、本質的に「バイナリ/ ld.so/whatnotをmmapしてから実行してください」であり、VMはRAMへのプロセスの実際のロードを処理します_と実行。ローカルの初期化されていない変数は、「ゼロページ」からmmapedになります-ゼロを含む特別な読み取り専用のコピーオンライトページ、ローカルの初期化された変数は、バイナリファイル自体からmmaped(再びコピーオンライト)されます。等.

20
qdot

Linuxカーネルは、fork()が呼び出されたときにコピーオンライトを実装します。 syscallが実行されると、親と子が共有するページは読み取り専用としてマークされます。

読み取り専用ページで書き込みを実行すると、2つのプロセス間でメモリが同一でなくなるため、ページがコピーされます。したがって、読み取り操作のみが実行されている場合、ページはまったくコピーされません。

25
mmk

Linuxはコピーオンライトを行います。 forkが新しいプロセスを作成すると、割り当てられたページは読み取り専用としてマークされ、親と子の間で共有されます。それらのいずれかがページを変更しようとすると、ページフォールトが生成され、その結果、ページがコピーされ、ページテーブルが適切に調整されます。

10
unxnut