摘要:可以看到,該結(jié)構(gòu)體存儲了關(guān)于變量值,有幾個(gè)變量指向該結(jié)構(gòu)體,變量類型,是否為引用變量等信息。這個(gè)就是寫時(shí)復(fù)制,在作怪,他沒有在賦值的時(shí)候就分裂成兩個(gè)結(jié)構(gòu)體,而是在我們改寫其中一個(gè)變量時(shí)發(fā)生效果,屬于一種慢復(fù)制也稱慢分裂。
想要走到技術(shù)的天花板,那么學(xué)習(xí)過程中在于知其然且知其所以然。
今天我們來討論一下PHP底層的寫時(shí)復(fù)制(也稱寫時(shí)分裂)。
首先我們先來看看一段代碼:
兩段代碼的輸出結(jié)果相信各位都知道,但是我們今天講講這之中發(fā)生了什么。
下圖是PHP存儲變量的結(jié)構(gòu)體(為方便講解已寫了注釋),zend.h在Zend目錄下。
可以看到,該結(jié)構(gòu)體存儲了關(guān)于變量值,有幾個(gè)變量指向該結(jié)構(gòu)體,變量類型,是否為引用變量等信息。
那么第一次打印發(fā)生了什么呢?變量的信息進(jìn)入了一個(gè)結(jié)構(gòu)體,相關(guān)如下:
$name = ‘傍晚八點(diǎn)半’;
$myName = $name;
此時(shí)$name和$myName共用一個(gè)結(jié)構(gòu)體的,refcount__gc為2,
我們發(fā)現(xiàn),$myName = $name;這個(gè)過程中并沒有主動(dòng)變成兩個(gè)結(jié)構(gòu)體(這也算PHP內(nèi)部實(shí)現(xiàn)優(yōu)化的一種,只用一個(gè)結(jié)構(gòu)體,省了內(nèi)存)。
那么當(dāng)代碼運(yùn)行到 $myName = ‘gzchen’; 的時(shí)候,結(jié)構(gòu)體如何變化呢?由于第一次輸出時(shí)是兩個(gè)變量共用結(jié)構(gòu)體,那么此時(shí)更改其中一個(gè)變量,會不會導(dǎo)致兩個(gè)值一起變化呢?純粹從結(jié)構(gòu)體的邏輯來看,是有可能的,畢竟大家共用著這個(gè)結(jié)構(gòu)體嘛。
那么我們看下第二次打印是怎么樣的情況,相關(guān)變化如下:
并沒有按照我們所想的將$name和$myName同時(shí)改成’gzchen’,而是復(fù)制多了一份結(jié)構(gòu)體出來,兩個(gè)結(jié)構(gòu)體分別對應(yīng)著$name和$myName。
這個(gè)就是寫時(shí)復(fù)制(Copy-on-write,COW)在作怪,他沒有在$myName = $name;賦值的時(shí)候就分裂成兩個(gè)結(jié)構(gòu)體,而是在我們改寫其中一個(gè)變量時(shí)發(fā)生效果,屬于一種慢復(fù)制(也稱慢分裂)。
偽代碼如下:
我們再看下另外一段代碼:
輸出為’b’,中途發(fā)生了什么?
其實(shí)foreach遍歷過程中,并不是直接操作$arr(原數(shù)組)的,而是會將$arr復(fù)制出一個(gè)$arrcopy(實(shí)際上是一個(gè)副本,我這里以$arrcopy代替),foreach在遍歷過程中操作的其實(shí)一直是$arrcopy,大概的流程是這樣:
和上面舉得例子其實(shí)是一個(gè)道理,我們可以看出,剛開始($arr = $arrcopy)還是共用一個(gè)結(jié)構(gòu)體的,但是$arr[$k] = $v又再次賦值,發(fā)生了寫時(shí)復(fù)制,結(jié)構(gòu)體就分裂了。
然后前面說過foreach操作的是$arrcopy,所以$arr的結(jié)構(gòu)體指針就被停留在第一位了(因?yàn)榻Y(jié)構(gòu)體不一樣了,$arrcopy沒辦法同步給$arr賦值了)。
其實(shí)這類技術(shù)通常只會在面試中用到,日常開發(fā)會用這種寫法的人終究還是少數(shù),暫時(shí)看不明白的朋友也不用太在意,只要知道有”寫時(shí)復(fù)制”這個(gè)情況出現(xiàn)就行了。
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://specialneedsforspecialkids.com/yun/21525.html
摘要:前面寫過一篇底層分析關(guān)于寫時(shí)復(fù)制今天來講講關(guān)于強(qiáng)制分裂的知識,簡單來說,強(qiáng)制分裂就是在引用變量主動(dòng)賦值前,該變量傳值賦值過,就會發(fā)生強(qiáng)制分裂。實(shí)際開發(fā)基本用不到這層原理,但在面試中強(qiáng)制分裂通常會和寫時(shí)復(fù)制一起考。 學(xué)習(xí)需要知其然而知其所以然,PHP底層相關(guān)就是這類知識。 前面寫過一篇《PHP底層分析:關(guān)于寫時(shí)復(fù)制(cow)》:https://segmentfault.com/a/119...
摘要:中基礎(chǔ)中的三大坑,遍歷,引用機(jī)制,數(shù)組。今天我們在講講中的一些奇怪現(xiàn)象。本文適合有一定基礎(chǔ)的。運(yùn)行流程共用一個(gè)結(jié)構(gòu)體開始遍歷數(shù)組,進(jìn)行判斷,拷貝數(shù)組是一個(gè)新的結(jié)構(gòu)體,操作的是新的結(jié)構(gòu)體。那么遍歷數(shù)組時(shí),全程與原數(shù)組無關(guān)。 PHP中基礎(chǔ)中的三大坑,foreach遍歷,引用機(jī)制&,數(shù)組。 今天我們在講講foreach中的一些奇怪現(xiàn)象。 在講解之前,可以先看看我其他相關(guān)的文章,屬于同一個(gè)大的...
摘要:將會產(chǎn)生強(qiáng)制分裂結(jié)構(gòu)體結(jié)構(gòu)體引用數(shù)組時(shí)的一些奇怪現(xiàn)象引用數(shù)組時(shí)的怪現(xiàn)象數(shù)組不會比較細(xì)致的檢查,多維數(shù)組存在。因此,判斷的時(shí)候,只會判斷外面一層的結(jié)構(gòu)體。中底層都離不開表。底層所有的變量都是放在中。 PHP編譯特點(diǎn) 編譯型語言 對于C語言,C++,編譯成機(jī)器碼(二進(jìn)制)來運(yùn)行。Java語言,把.java 編譯成.class, 稱為bytecode(字節(jié)碼),由jvm來運(yùn)行 解釋型語言 解...
摘要:只有在真正需要使用資源時(shí)才占用資源,寫時(shí)復(fù)制通常能減少資源的占用。基礎(chǔ)方面規(guī)范新特性性能調(diào)優(yōu)垃圾回收機(jī)制安全攻擊原理和防范攻擊原理和防范注入攻擊防范密碼哈希計(jì)算機(jī)網(wǎng)絡(luò)協(xié)議協(xié)議連接過程 從一個(gè)例子說起: 很明顯在這段代碼執(zhí)行以后,$var_dup 的值應(yīng)該還是laruence, 那么這又是怎么實(shí)現(xiàn)的呢?這就是 PHP 的 copy on write 機(jī)制: PHP 在修改一個(gè)變量以前,...
摘要:本文主要是針對,的話可以移步到慶哥的博客看,還有就是小菜我讀的是內(nèi)核剖析這本書。接下來我會使用到來調(diào)試源碼本文有參照博客中的部分內(nèi)容以及代碼。 前言 工作+實(shí)習(xí)快一年了,搞php后端開發(fā),一直很迷茫怎么提高自己,就先從php源碼開始吧,本人比較菜,本文章寫的比較趕時(shí)間,所以有什么錯(cuò)誤或者漏掉的地方,望各位大神指正,多交流才能成長嘛,嘿嘿。本文主要是針對php7,php5的話可以移步到慶...
閱讀 3616·2021-11-24 09:39
閱讀 2546·2021-11-15 11:37
閱讀 2211·2021-11-11 16:55
閱讀 5155·2021-10-14 09:43
閱讀 3703·2021-10-08 10:05
閱讀 3006·2021-09-13 10:26
閱讀 2327·2021-09-08 09:35
閱讀 3535·2019-08-30 15:55