詳しくはLinuxを書く時、コピー技術(copy-on-write)は必ず読みます。
2654 ワード
COW技術初見
Linuxプログラムでは、fork()は親プロセスと全く同じサブルーチンを生成しますが、子プロセスはその後、execシステムで呼び出されることが多く、効率を考慮して、linuxでは、「書き込み時コピー」技術を導入しました。つまり、プロセス空間の各セグメントの内容だけが変化する場合、親プロセスの内容をサブルーチンにコピーします。
では、サブプロセスの物理的な空間にコードがありません。どうやって命令を取ってexecシステムの呼び出しを実行しますか?
forkの後、execの前の2つのプロセスは同じ物理空間(メモリ領域)を使用し、サブルーチンのコードセグメント、データセグメント、スタックは親プロセスを指す物理空間であり、つまり、両者の仮想空間は異なり、その対応する物理空間は一つである。親子プロセスにおいて、該当区間を変更する行為が発生した場合、サブプロセスに対応するセグメントに物理空間を割り当てます。execのためでなければ、カーネルは、子プロセスのデータセグメント、スタックセグメントにそれぞれの物理空間を割り当て(これまでの両方にはそれぞれのプロセス空間があり、互いに影響しない)、コードセグメントは親プロセスの物理空間を共有し続ける(両者のコードは完全に同じ)。execの場合は、両方の実行コードが異なるため、サブルーチンのコードセグメントは、個別の物理空間を割り当てられます。
インターネットで見た詳細な問題は、forkの後にカーネルがサブプロセスをキューの前に並べて、子プロセスを先に実行させ、親プロセスの実行による書き込み時のコピーを防ぐため、子プロセスがexecシステム呼び出しを実行し、無意味なコピーによって効率が低下します。
COWで詳しく述べる
今は父のプロセスP 1があります。これは一つの主体です。魂があり、体もあります。現在、その仮想アドレス空間(対応するデータ構造表現がある)には、本文、データセグメント、スタック、スタックの4つの部分があり、従って、カーネルはこの4つの部分のために自物理ブロックに割り当てられる。つまり、本文のブロック、データのブロック、ブロック、スタックのブロックです。どのように分配するかについては,これは内核で行うことであり,ここでは詳述しない。
1.現在P 1はプロセスのためのfork()関数でサブプロセスP 2を作成します。
カーネル:
(1)P 1の本文、データセグメント、スタックの4つの部分をコピーします。内容は同じです。
(2)この4つの部分に物理ブロックを割り当て、P 2の部分(P 1の本文セグメントの物理ブロックとして、P 2に本文ブロックを割り当てず、P 2の本文セグメントをP 1の本文ブロックに向ける)、データセグメント(P 2自身のデータブロックに対応するブロックを割り当てる)、ヒープ(P 2自身のブロック)、スタック(P 2自身のスタックブロック)、スタック(P 2自身のブロック)を割り当てる。下図のように、左から右に大きい方向の矢印はコピー内容を表します。
2.書く時のコピー技術
書き込み時のコピー技術:カーネルは新しく生成されたサブプロセスのために仮想空間構造を作成し、それらは親プロセスの仮想空間構造にコピーされますが、これらのセグメントに物理メモリを割り当てずに、親プロセスの物理空間を共有します。親子プロセスには、該当するセグメントの行が発生した場合、サブプロセスに対応するセグメントに物理空間を割り当てます。
3.v fork
vforkのやり方はもっと簡単で粗暴で、カーネルは子プロセスの仮想アドレス空間も創建しなくなりました。直接に父プロセスの仮想空間を共有しました。もちろん、このようなやり方は父プロセスの物理空間を共有しました。
締め括りをつける
従来のfork()システムは、すべてのリソースを新たに作成するプロセスに直接コピーするように呼び出します。このような実現はあまりにも簡単で効率が悪いです。コピーしたデータは共有しないかもしれません。もっと悪い場合は、新しいプロセスがすぐに新しい映像を実行するつもりなら、すべてのコピーは無駄になります。
Linuxのfork()は書く時にコピーしたページを使って実現します。コピーは、データのコピーを遅らせたり、免除したりする技術です。カーネルはアドレス空間全体をコピーするのではなく、親プロセスと子プロセスにコピーを共有させる。書き込みが必要な場合だけ、データをコピーして、各プロセスにそれぞれのコピーを持たせます。つまり、リソースのコピーは書き込みが必要な時にのみ行われ、それまでは読み取り専用で共有されています。この技術はアドレス空間のページのコピーを実際に書き込みが発生した時に遅らせます。
ページが全く書かれていない場合、例えば、fork()の直後にexec()を呼び出すと、コピーする必要がなく、fork()の実際のオーバーヘッドは親プロセスのページ表をコピーし、子プロセスに一意のプロセス記述子を作成することである。一般的には、プロセスが作成されると、すぐに実行可能なファイルが実行されます。この最適化は、ほとんど使われないデータの大量コピーを避けることができます。Unixはプロセスの高速実行能力を強調するので、この最適化はとても重要です。
以上の詳細はLinuxを書く時にコピー技術(copy-on-write)を必ず読んでください。つまり、小編集は皆さんに共有している内容の全部です。参考にしてもらいたいです。どうぞよろしくお願いします。
Linuxプログラムでは、fork()は親プロセスと全く同じサブルーチンを生成しますが、子プロセスはその後、execシステムで呼び出されることが多く、効率を考慮して、linuxでは、「書き込み時コピー」技術を導入しました。つまり、プロセス空間の各セグメントの内容だけが変化する場合、親プロセスの内容をサブルーチンにコピーします。
では、サブプロセスの物理的な空間にコードがありません。どうやって命令を取ってexecシステムの呼び出しを実行しますか?
forkの後、execの前の2つのプロセスは同じ物理空間(メモリ領域)を使用し、サブルーチンのコードセグメント、データセグメント、スタックは親プロセスを指す物理空間であり、つまり、両者の仮想空間は異なり、その対応する物理空間は一つである。親子プロセスにおいて、該当区間を変更する行為が発生した場合、サブプロセスに対応するセグメントに物理空間を割り当てます。execのためでなければ、カーネルは、子プロセスのデータセグメント、スタックセグメントにそれぞれの物理空間を割り当て(これまでの両方にはそれぞれのプロセス空間があり、互いに影響しない)、コードセグメントは親プロセスの物理空間を共有し続ける(両者のコードは完全に同じ)。execの場合は、両方の実行コードが異なるため、サブルーチンのコードセグメントは、個別の物理空間を割り当てられます。
インターネットで見た詳細な問題は、forkの後にカーネルがサブプロセスをキューの前に並べて、子プロセスを先に実行させ、親プロセスの実行による書き込み時のコピーを防ぐため、子プロセスがexecシステム呼び出しを実行し、無意味なコピーによって効率が低下します。
COWで詳しく述べる
今は父のプロセスP 1があります。これは一つの主体です。魂があり、体もあります。現在、その仮想アドレス空間(対応するデータ構造表現がある)には、本文、データセグメント、スタック、スタックの4つの部分があり、従って、カーネルはこの4つの部分のために自物理ブロックに割り当てられる。つまり、本文のブロック、データのブロック、ブロック、スタックのブロックです。どのように分配するかについては,これは内核で行うことであり,ここでは詳述しない。
1.現在P 1はプロセスのためのfork()関数でサブプロセスP 2を作成します。
カーネル:
(1)P 1の本文、データセグメント、スタックの4つの部分をコピーします。内容は同じです。
(2)この4つの部分に物理ブロックを割り当て、P 2の部分(P 1の本文セグメントの物理ブロックとして、P 2に本文ブロックを割り当てず、P 2の本文セグメントをP 1の本文ブロックに向ける)、データセグメント(P 2自身のデータブロックに対応するブロックを割り当てる)、ヒープ(P 2自身のブロック)、スタック(P 2自身のスタックブロック)、スタック(P 2自身のブロック)を割り当てる。下図のように、左から右に大きい方向の矢印はコピー内容を表します。
2.書く時のコピー技術
書き込み時のコピー技術:カーネルは新しく生成されたサブプロセスのために仮想空間構造を作成し、それらは親プロセスの仮想空間構造にコピーされますが、これらのセグメントに物理メモリを割り当てずに、親プロセスの物理空間を共有します。親子プロセスには、該当するセグメントの行が発生した場合、サブプロセスに対応するセグメントに物理空間を割り当てます。
3.v fork
vforkのやり方はもっと簡単で粗暴で、カーネルは子プロセスの仮想アドレス空間も創建しなくなりました。直接に父プロセスの仮想空間を共有しました。もちろん、このようなやり方は父プロセスの物理空間を共有しました。
締め括りをつける
従来のfork()システムは、すべてのリソースを新たに作成するプロセスに直接コピーするように呼び出します。このような実現はあまりにも簡単で効率が悪いです。コピーしたデータは共有しないかもしれません。もっと悪い場合は、新しいプロセスがすぐに新しい映像を実行するつもりなら、すべてのコピーは無駄になります。
Linuxのfork()は書く時にコピーしたページを使って実現します。コピーは、データのコピーを遅らせたり、免除したりする技術です。カーネルはアドレス空間全体をコピーするのではなく、親プロセスと子プロセスにコピーを共有させる。書き込みが必要な場合だけ、データをコピーして、各プロセスにそれぞれのコピーを持たせます。つまり、リソースのコピーは書き込みが必要な時にのみ行われ、それまでは読み取り専用で共有されています。この技術はアドレス空間のページのコピーを実際に書き込みが発生した時に遅らせます。
ページが全く書かれていない場合、例えば、fork()の直後にexec()を呼び出すと、コピーする必要がなく、fork()の実際のオーバーヘッドは親プロセスのページ表をコピーし、子プロセスに一意のプロセス記述子を作成することである。一般的には、プロセスが作成されると、すぐに実行可能なファイルが実行されます。この最適化は、ほとんど使われないデータの大量コピーを避けることができます。Unixはプロセスの高速実行能力を強調するので、この最適化はとても重要です。
以上の詳細はLinuxを書く時にコピー技術(copy-on-write)を必ず読んでください。つまり、小編集は皆さんに共有している内容の全部です。参考にしてもらいたいです。どうぞよろしくお願いします。