摘要:但是對于結(jié)構(gòu)體中的和字段我們一直都沒有詳細(xì)介紹過,而這兩個字段其實(shí)是和變量之間賦值的原理有著密切的關(guān)系的。
上周我們從底層的角度介紹了php變量從生成->常量賦值->銷毀的完整生命周期(不了解的同學(xué)可以翻看一下前面的文章php底層原理之變量(一)),但是我們留了一個思考,不知道大家有答案了沒,變量之間的賦值在底層又是如何實(shí)現(xiàn)的呢?
變量之間賦值php變量的zval結(jié)構(gòu),我們已經(jīng)介紹了很多遍了,這里我們就不再多作介紹了。但是對于zval結(jié)構(gòu)體中的refcount__gc和is_ref__gc字段我們一直都沒有詳細(xì)介紹過,而這兩個字段其實(shí)是和變量之間賦值的原理有著密切的關(guān)系的。所以,我們這次從幾個例子入手,了解這兩個字段的變化和由此帶來的原理知識
寫時復(fù)制原理舉例:
$a = "許錚的技術(shù)成長之路"; $b = $a; xdebug_debug_zval("a", "b");
結(jié)果:
a: (refcount=2, is_ref=0)="許錚的技術(shù)成長之路" b: (refcount=2, is_ref=0)="許錚的技術(shù)成長之路"
看到這里,大家可能會比較蒙。不是變量賦值了么?應(yīng)該發(fā)生值拷貝了呀?怎么兩個變量的引用計(jì)數(shù)不是1,而是2呢?
那是因?yàn)椋?strong>php在設(shè)計(jì)的時候,為了節(jié)省內(nèi)存,所以在變量之間賦值時,對于值相同的兩個變量,會共用一塊內(nèi)存,也就是會在全局符號表內(nèi)將變量b的變量指針指向變量a指向的同一個zval結(jié)構(gòu)體,而只有當(dāng)變量的zval結(jié)構(gòu)發(fā)生變化時,才會發(fā)生變量容器復(fù)制的內(nèi)存變化,也因此叫做寫時復(fù)制原理
那什么時候會發(fā)生寫時復(fù)制原理呢?
寫時復(fù)制原理觸發(fā)時機(jī):
php在修改一個變量時,如果發(fā)現(xiàn)變量的refcount>1,則會執(zhí)行變量容器的內(nèi)存復(fù)制
舉例:
$a = "許錚的技術(shù)成長之路"; $b = $a; //此時變量a和變量b共同指向同一個變量容器,即refcount>1 $b = "許錚的技術(shù)成長之路1" //觸發(fā)寫時復(fù)制機(jī)制 xdebug_debug_zval("a", "b");
結(jié)果:
a: (refcount=1, is_ref=0)="許錚的技術(shù)成長之路" b: (refcount=1, is_ref=0)="許錚的技術(shù)成長之路1"寫時改變原理
變量之間的賦值我們搞清楚了,那么變量和引用之間的賦值呢?我們還是通過舉例來說明
舉例:
$a = "許錚的技術(shù)成長之路"; $b = &$a; xdebug_debug_zval("a", "b");
結(jié)果:
a: (refcount=2, is_ref=1)="許錚的技術(shù)成長之路" b: (refcount=2, is_ref=1)="許錚的技術(shù)成長之路"
此時,我們發(fā)現(xiàn),變量a和b的refcount還是2,只不過is_ref變成了1,那是因?yàn)樵趯⒆兞縜引用賦值給變量b時,在原變量容器上作了修改,將is_ref變成了1,且refcount+1
那如果引用賦值的基礎(chǔ)上又發(fā)生了變量的改變了呢?
舉例:
$a = "許錚的技術(shù)成長之路"; $b = &$a; $b = "許錚的技術(shù)成長之路1" xdebug_debug_zval("a", "b");
結(jié)果:
a: (refcount=2, is_ref=1)="許錚的技術(shù)成長之路1" b: (refcount=2, is_ref=1)="許錚的技術(shù)成長之路1"
是不是覺得很神奇?變量b和變量a的值一起發(fā)生改變了~其實(shí)這是因?yàn)橛|發(fā)了寫時改變原理
寫時改變原理觸發(fā)時機(jī):
is_ref為1的變量容器在被賦值之前,優(yōu)先檢查變量容器的is_ref是否等于1,如果為1,則不進(jìn)行寫時復(fù)制,而是在原變量容器基礎(chǔ)上作內(nèi)容修改;而如果將is_ref為1的變量容器賦值給其他變量時,則會立即觸發(fā)寫時復(fù)制
那么如果把剛剛舉得幾個例子合并在一起呢?最后結(jié)果又是什么呢?
舉例:
$a = "許錚的技術(shù)成長之路"; $b = $a; $c = &$a; xdebug_debug_zval("a", "b", "c");
結(jié)果:
a: (refcount=2, is_ref=1)="許錚的技術(shù)成長之路" b: (refcount=1, is_ref=0)="許錚的技術(shù)成長之路" c: (refcount=2, is_ref=1)="許錚的技術(shù)成長之路"
整體執(zhí)行過程是這樣的,當(dāng)執(zhí)行到第二行時,變量容器的refcount會變成2,變量a和變量b共享同一個變量容器;當(dāng)執(zhí)行到第三行時,因?yàn)閷⒆兞縜的引用賦值給變量c,但是變量b和變量a已經(jīng)共享了同一個變量容器,此時變量容器如果要發(fā)生改變,因?yàn)閞efcount>2,所以會發(fā)生寫時復(fù)制,將變量a和變量b分離,之后將變量a引用賦值給變量c時,則會原基礎(chǔ)上進(jìn)行修改,is_ref變成1,且refcount變成2
思考那么,下面的這個例子,最終結(jié)果是什么呢?歡迎大家在下方留言或私信我~
舉例:
$a = "許錚的技術(shù)成長之路"; $b = $a; $c = &$a; $d = $a; $e = "許錚的技術(shù)成長之路1" $a = $e; xdebug_debug_zval("a", "b", "c", "d", "e");
如果你喜歡我的文章,請點(diǎn)贊支持我下,并歡迎關(guān)注我的專欄,每周都會有原創(chuàng)且有深度的文章奉上喲~
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/31087.html
摘要:數(shù)組是最常用的數(shù)據(jù)類型,同時容易上手也得益于其強(qiáng)大的數(shù)組,但是數(shù)組在中是如何實(shí)現(xiàn)的呢首先,我們還是先了解下相關(guān)的數(shù)據(jù)結(jié)構(gòu),為下面的內(nèi)容打好基礎(chǔ)哈希表哈希表,顧名思義,即將不同的關(guān)鍵字映射到不同單元的一種數(shù)據(jù)結(jié)構(gòu)。 數(shù)組是PHPer最常用的數(shù)據(jù)類型,同時php容易上手也得益于其強(qiáng)大的數(shù)組,但是數(shù)組在php中是如何實(shí)現(xiàn)的呢? 首先,我們還是先了解下相關(guān)的數(shù)據(jù)結(jié)構(gòu),為下面的內(nèi)容打好基礎(chǔ) 哈希...
摘要:對于來說,變量有全局變量和局部變量之分那么,他們都是存儲到一個哈希表內(nèi)了么其實(shí)不是的,變量存儲也有作用域的概念。 上次跟大家講了垃圾回收機(jī)制后,有些小伙伴對底層原理比較感興趣,私信問我了一些關(guān)于變量的相關(guān)知識,既然大家對變量比較感興趣,那么這次我們來系統(tǒng)的講一下變量的底層原理 變量結(jié)構(gòu) 首先,我們還是先擺上我們的zval結(jié)構(gòu)體,即php所有變量都會以zval結(jié)構(gòu)體的形式實(shí)現(xiàn) struc...
摘要:總結(jié)垃圾回收機(jī)制以的引用計(jì)數(shù)機(jī)制為基礎(chǔ)以前只有該機(jī)制同時使用根緩沖區(qū)機(jī)制,當(dāng)發(fā)現(xiàn)有存在循環(huán)引用的時,就會把其投入到根緩沖區(qū),當(dāng)根緩沖區(qū)達(dá)到配置文件中的指定數(shù)量后,就會進(jìn)行垃圾回收,以此解決循環(huán)引用導(dǎo)致的內(nèi)存泄漏問題開始引入該機(jī)制 php垃圾回收機(jī)制,對于PHPer來說是一個不陌生但是又不是很熟悉的內(nèi)容。那么php是怎么實(shí)現(xiàn)對不需要的內(nèi)存進(jìn)行回收的呢? php變量的內(nèi)部存儲結(jié)構(gòu) 首先還是...
摘要:弱類型語言一個變量的類型并不是一開始就確定不變的,運(yùn)行中才會確定并可能發(fā)生隱式或顯示的類型轉(zhuǎn)換。引擎組件的模式降低內(nèi)部耦合。 一、PHP設(shè)計(jì)理念及特點(diǎn) 多進(jìn)程模型:由于PHP是多進(jìn)程模型,不同請求間互不干涉,這樣保證了一個請求掛掉不會對全盤服務(wù)造成影響,PHP也早支持多線程模型。弱類型語言:一個變量的類型并不是一開始就確定不變的,運(yùn)行中才會確定并可能發(fā)生隱式或顯示的類型轉(zhuǎn)換。引擎(Ze...
摘要:雖然有了十全的計(jì)劃,但如何高效率去記住上面那么多東西是一個大問題,看看我是怎么做的。 前言 前一篇文章講述了我在三月份毫無準(zhǔn)備就去面試的后果,一開始心態(tài)真的爆炸,但是又不服氣,一想到每次回來后家人朋友問我面試結(jié)果的期待臉,越覺得必須付出的行動來證明自己了。 面經(jīng)傳送門:一個1年工作經(jīng)驗(yàn)的PHP程序員是如何被面試官虐的? 下面是我花費(fèi)兩個星期做的準(zhǔn)備,主要分三部分: 有計(jì)劃——計(jì)劃好...
閱讀 2900·2019-08-30 15:55
閱讀 2009·2019-08-30 14:02
閱讀 1248·2019-08-29 15:23
閱讀 1014·2019-08-29 11:27
閱讀 468·2019-08-26 11:43
閱讀 3196·2019-08-26 10:32
閱讀 1261·2019-08-23 14:41
閱讀 3304·2019-08-23 14:41