PHP中copy on write寫時(shí)復(fù)制機(jī)制介紹
什么是寫時(shí)復(fù)制(Copy On Write)?
答:在復(fù)制一個(gè)對象的時(shí)候并不是真正的把原先的對象復(fù)制到內(nèi)存的另外一個(gè)位置上,而是在新對象的內(nèi)存映射表中設(shè)置一個(gè)指針,指向源對象的位置,并把那塊內(nèi)存的Copy-On-Write位設(shè)置為1.這樣,在對新的對象執(zhí)行讀操作的時(shí)候,內(nèi)存數(shù)據(jù)不發(fā)生任何變動(dòng),直接執(zhí)行讀操作;而在對新的對象執(zhí)行寫操作時(shí),將真正的對象復(fù)制到新的內(nèi)存地址中,并修改新對象的內(nèi)存映射表指向這個(gè)新的位置,并在新的內(nèi)存位置上執(zhí)行寫操作。
這個(gè)技術(shù)需要跟虛擬內(nèi)存和分頁同時(shí)使用,好處就是在執(zhí)行復(fù)制操作時(shí)因?yàn)椴皇钦嬲膬?nèi)存復(fù)制,而只是建立了一個(gè)指針,因而大大提高效率。但這不是一直成立的,如果在復(fù)制新對象之后,大部分對象都還需要繼續(xù)進(jìn)行寫操作會(huì)產(chǎn)生大量的分頁錯(cuò)誤,得不償失。所以COW高效的情況只是在復(fù)制新對象之后,在一小部分的內(nèi)存分頁上進(jìn)行寫操作。
在PHP 內(nèi)核中同樣使用了寫時(shí)復(fù)制機(jī)制來避免在賦值時(shí)導(dǎo)致內(nèi)存增加,比如我們在使用foreach循環(huán)體時(shí),可以發(fā)現(xiàn)其中的奧秘,示例代碼:
$m1 = memory_get_usage();
$str=<<<EOF
aaaaaaaaaaaaaa
aaaaaaaaaaaaaa
aaaaaaaaaaaaaa
EOF;
$arr = explode("\n", $str);
$count=0;
foreach($arr as $v){
$count++;
//$v='aaaaaaaaaaaaaa';
}
$m2 = memory_get_usage();
echo $m2-$m1;
當(dāng)我們執(zhí)行此代碼時(shí)會(huì)得到內(nèi)存占用為:788
$m1 = memory_get_usage();
$str=<<<EOF
aaaaaaaaaaaaaa
aaaaaaaaaaaaaa
aaaaaaaaaaaaaa
EOF;
$arr = explode("\n", $str);
$count=0;
foreach($arr as $v){
$count++;
$v='aaaaaaaaaaaaaa';
}
$m2 = memory_get_usage();
echo $m2-$m1;
當(dāng)我們?nèi)∠?//$v='aaaaaaaaaaaaaa'; 的注釋,此時(shí)內(nèi)存占用數(shù)值為:840,注意內(nèi)存增長了。
$m1 = memory_get_usage();
$str=<<<EOF
aaaaaaaaaaaaaa
aaaaaaaaaaaaaa
aaaaaaaaaaaaaa
EOF;
$arr = explode("\n", $str);
$count=0;
foreach($arr as &$v){
$count++;
//$v='aaaaaaaaaaaaaa';
}
$m2 = memory_get_usage();
echo $m2-$m1;
當(dāng)我們將foreach中的$v 改寫為 &$v 時(shí),不管是否注釋循環(huán)體中對$v的注釋,我們都可以得到內(nèi)存占用為:788
這里就說明了COW機(jī)制的介入,當(dāng)我們在foreach循環(huán)中純粹的只用到對$v 的讀操作時(shí),PHP內(nèi)核會(huì)將$v這個(gè)變量的內(nèi)存地址指向到$arr中數(shù)組這一索引的內(nèi)存地址,并沒有將數(shù)組中的數(shù)據(jù)復(fù)制一份給到變量$v,此時(shí)內(nèi)存占用情況和使用&$v 是一樣的。但當(dāng)我們在循環(huán)體內(nèi)對$v進(jìn)行寫操作時(shí),寫時(shí)復(fù)制機(jī)制就被激活了,此時(shí)PHP會(huì)重新開辟一段內(nèi)存空間給到$v變量,而將原先$v指向數(shù)組的內(nèi)存地址給斷開了,此時(shí)內(nèi)存必然就會(huì)增長了。
這里可以得出另外一個(gè)結(jié)論:當(dāng)我們在讀取大數(shù)據(jù)的時(shí)候,要注意COW機(jī)制引入的內(nèi)存增長影響,同樣避免不必要的對變量寫,可以提高代碼運(yùn)行性能。
相關(guān)文章
php獲得網(wǎng)站訪問統(tǒng)計(jì)信息類Compete API用法實(shí)例
這篇文章主要介紹了php獲得網(wǎng)站訪問統(tǒng)計(jì)信息類Compete API用法,實(shí)例分析了php使用curl獲取Compete統(tǒng)計(jì)網(wǎng)站信息的技巧,具有一定參考借鑒價(jià)值,需要的朋友可以參考下2015-04-04php調(diào)用mysql數(shù)據(jù) dbclass類
php調(diào)用mysql數(shù)據(jù)數(shù)據(jù)庫操作類,dbclass類,需要的朋友可以參考下。2011-05-05Thinkphp結(jié)合AJAX長輪詢實(shí)現(xiàn)PC與APP推送詳解
這篇文章主要給大家介紹了關(guān)于Thinkphp結(jié)合AJAX長輪詢實(shí)現(xiàn)PC與APP推送的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來一起看看吧。2017-07-07Ping服務(wù)的php實(shí)現(xiàn)方法,讓網(wǎng)站快速被收錄
這篇博文繼續(xù)說說這個(gè)ping服務(wù)的問題,首先歸納和總結(jié)以下資料2012-02-02