從乙個例子說起:
<?php
$foo = 1;
$bar = $foo;
echo $foo + $bar;
變數 $foo 賦值給變數 $bar,這兩個變數具有相同的值,沒有必要新申請記憶體空間,他們可以共享同一塊記憶體。在很多場景下php 的 cow 對記憶體進行優化。比如:變數的多次賦值、函式引數傳遞,並在函式體內修改實參等。
這是一段摘自鳥哥部落格的例子,說的比較清楚,就直接貼過來了。
<?php
$var = "laruence";
$var_dup = $var;
$var = 1;
?>
很明顯在這段**執行以後,$var_dup 的值應該還是」laruence」, 那麼這又是怎麼實現的呢?這就是 php 的 copy on write 機制:
php 在修改乙個變數以前,會首先檢視這個變數的 refcount,如果 refcount 大於1,php 就會執行乙個分離的例程, 對於上面的**,當執行到第三行的時候,php 發現 $var 指向的 zval 的 refcount 大於1,那麼 php 就會複製乙個新的 zval 出來,將原 zval 的 refcount 減 1,並修改 symbol_table,使得 $var 和 $var_dup 分離(separation)。這個機制就是所謂的 copy on write(寫時複製)。
寫時複製(copy on write,也縮寫為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)
var_dump(memory_get_usage());
執行結果:
$ php t . php
int(630904)
int(10479840)
int(10479944)
int(10480040)
記憶體並沒有顯著提高。
多個相同值的變數共用同一塊記憶體的確節省了記憶體空間,但變數的值是會發生變化的,如果在上面的例子中, 指向同一記憶體的值發生了變化(或者可能發生變化),就需要將變化的值「分離」出去,這個「分離」的操作, 就是「複製」。
ref_count和is_ref是定義於zval結構體中
is_ref標識是不是使用者使用 & 的強制引用;
ref_count是引用計數,用於標識此zval被多少個變數引用,即cow的自動引用,為0時會被銷毀;
注:由此可見, $a=$b; 與 $a=&$b; 在php對記憶體的使用上沒有區別(值不變化時);
相信大家也可以了解到php中cow的實現原理: php 中的 cow 基於引用計數ref_count 和 is_ref 實現, 多乙個變數指標,就將 ref_count 加 1, 反之減去 1,減到 0 就銷毀; 同理,多乙個強制引用 &,就將 is_ref 加 1,反之減去 1。
PHP寫時複製, 變數複製和物件複製不同
2016年3月18日 15 09 28 星期五 一直以為php物件也是寫時複製.其實 php的變數是寫時複製,物件是引用的 寫時複製 a b 如果 b的內容不改變,a和 b指向同一塊記憶體 如果 b內容改變了,a的內容是不會改變的,而是為 b重新申請空間存放資料 但是 物件 objtest1 obj...
PHP中copy on write寫時複製機制介紹
什麼是寫時複製 copy on write 答 在複製乙個物件的時候並不是真正的把原先的物件複製到記憶體的另外乙個位置上,而是在新物件的記憶體對映表中設定乙個指標,指向源物件的位置,並把那塊記憶體的copy on write位設定為1.這樣,在對新的物件執行讀操作的時候,記憶體資料不發生任何變動,直...
Copy On Write寫時複製
copy on write解決的問題 早期unix系統建立程序的方式存在缺陷 當發出fork 系統呼叫時,核心原樣複製父程序的整個位址空間並把複製的那乙份分配給子程序。這種行為是非常耗時的,因為它需要 為子程序的頁表分配頁幀 為子程序的頁分配頁幀 初始化子程序的頁表 把父程序的頁複製到子程序相應的頁...