例から始めましょう:
<?php $foo = 1; $bar = $foo; echo $foo + $bar;
変数 $foo は変数 $bar に割り当てられます。これら 2 つの変数は同じ値を持ちます。新しいメモリ空間を申請する必要はありません。それらは共有できます。同じ記憶。 PHP の COW は、多くのシナリオでメモリを最適化します。例: 変数の複数の代入、関数パラメータの受け渡し、関数本体内の実際のパラメータの変更など。
「コピー」とは
これは、ニアオ兄弟のブログから引用した例です。より明確になるため、直接投稿しました。
<?php $var = "laruence"; $var_dup = $var; $var = 1; ?>
このコードが実行された後も、$var_dup の値は依然として "laruence" であるはずです。では、これはどのように実現されるのでしょうか?これは PHP のコピーオンライトメカニズムです:
変数を変更する前に、PHP はまず変数の refcount をチェックします。refcount が 1 より大きい場合、PHP は別のルーチンを実行します。上記のコードの場合、 3 行目を実行すると、PHP は $var が指す zval の refcount が 1 より大きいことを検出し、PHP は新しい zval をコピーし、元の zval の refcount を 1 減らして、$var と$var_dup 分離。このメカニズムは、いわゆるコピー オン ライトです。
コピー オン ライト アプリケーション シナリオ
コピー オン ライト (COW とも略される) には、Linux でのプロセスのメモリのコピーなど、多くのアプリケーション シナリオがあります。には、C、STL などのさまざまなプログラミング言語で同様のアプリケーションがあります。 COW は一般的に使用される最適化手法であり、次のように分類できます。 リソースの遅延割り当て。リソースは実際に必要な場合にのみ占有されるため、通常はコピーオンライトによりリソースの使用量を削減できます。
PHP COW がメモリ使用量を最適化することを証明する例:
<?php $j = 1; var_dump(memory_get_usage()); $tipi = array_fill(0, 100000, 'php-internal'); var_dump(memory_get_usage()); $tipi_copy = $tipi; var_dump(memory_get_usage()); foreach ($tipi_copy as $i) { $j += count($i); } var_dump(memory_get_usage());
実行結果:
$ php t . php int(630904) int(10479840) int(10479944) int(10480040)
メモリは大幅には改善されません。
「コピーオンライト」の原理
同じ値の複数の変数で同じメモリを共有するとメモリ領域は節約されますが、変数の値は上記の例で、同じメモリを指す値が変化した(または変化する可能性がある)場合、変化した値を「分離」する必要があり、この「分離」操作が「コピー」です。
PHP では、同じ zval アドレスが複数の変数によって共有されているかどうかを区別するために、Zend エンジンは識別用に 2 つの変数 ref_count と is_ref を導入します。
ref_count と is_ref は次のように定義されています。 zval 構造体本文の
is_ref マークは、& を使用するユーザーによる必須の参照です。
ref_count は参照カウントであり、この zval が参照される変数の数を識別するために使用されます。 、COW の自動参照は、0 の場合は破棄されます;
注: $a=$b; と $a=&$ の間で PHP のメモリ使用量に違いがないことがわかります。 b; (値が変化しない場合);
PHP における COW の実装原理は皆さんも理解できると思います: PHP における COW は参照カウント ref_count と is_ref に基づいて実装されます。ポインタ、ref_count は 1 だけ増加し、それ以外の場合は 1 減算され、0 に減少すると破棄されます。同じ理由で、もう 1 つ必須の参照 & がある場合、is_ref は 1 だけ増加し、そうでない場合は 1 だけ減算されます。 。
以上がPHP コピーオンライト (Copy On Write)の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。