欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

詳解PHP的引用計數(shù)

 更新時間:2021年04月28日 10:55:39   作者:硬核項目經(jīng)理  
這篇文章主要介紹了PHP的引用計數(shù)的相關(guān)資料,幫助大家更好的理解和學(xué)習(xí)使用PHP,感興趣的朋友可以了解下

什么是引用計數(shù)

在PHP的數(shù)據(jù)結(jié)構(gòu)中,引用計數(shù)就是指每一個變量,除了保存了它們的類型和值之外,還額外保存了兩個內(nèi)容,一個是當(dāng)前這個變量是否被引用,另一個是引用的次數(shù)。為什么要多保存這樣兩個內(nèi)容呢?當(dāng)然是為了垃圾回收(GC)。也就是說,當(dāng)引用次數(shù)為0的時候,這個變量就沒有再被使用了,就可以通過 GC 來進(jìn)行回收,釋放占用的內(nèi)存資源。任何程序都不能無限制的一直占用著內(nèi)存資源,過大的內(nèi)存占用往往會帶來一個嚴(yán)重的問題,那就是內(nèi)存泄露,而 GC 就是PHP底層自動幫我們完成了內(nèi)存的銷毀,而不用像 C 一樣必須去手動地 free 。

怎么查看引用計數(shù)?

我們需要安裝 xdebug 擴(kuò)展,然后使用 xdebug_debug_zval() 函數(shù)就可以看到指定內(nèi)存的詳細(xì)信息了,比如:

$a = "I am a String";
xdebug_debug_zval('a');
// a: (refcount=1, is_ref=0)='I am a String'

從上述內(nèi)容中可以看出,這個 $a 變量的內(nèi)容是 I am a String 這樣一個字符串。而括號中的 refcount 就是引用次數(shù),is_ref 則是說明這個變量是否被引用。我們通過變量賦值來看看這個兩個參數(shù)是如何變化的。

$b = $a;
xdebug_debug_zval('a');
// a: (refcount=1, is_ref=0)='I am a String'

$b = &$a;
xdebug_debug_zval('a');
// a: (refcount=2, is_ref=1)='I am a String'

當(dāng)我們進(jìn)行普通賦值后,refcount 和 is_ref 沒有任何變化,但當(dāng)我們進(jìn)行引用賦值后,可以看到 refcount 變成了2,is_ref 變成了1。這也就是說明當(dāng)前的 \a 變量被引用賦值了,它的內(nèi)存符號表服務(wù)于a變量被引用賦值了,它的內(nèi)存符號表服務(wù)于a 和 $b 兩個變量。

$c = &$a;
xdebug_debug_zval('a');
// a: (refcount=3, is_ref=1)='I am a String'

unset($c, $b);
xdebug_debug_zval('a');
// a: (refcount=1, is_ref=1)='I am a String'

$b = &$a;
$c = &$a;
$b = "I am a String new";
xdebug_debug_zval('a');
// a: (refcount=3, is_ref=1)='I am a String new'

unset($a);
xdebug_debug_zval('a');
// a: no such symbol

繼續(xù)增加一個 c 的引用賦值,可以看到 refcount 會繼續(xù)增加。然后 unset 掉c的引用賦值,可以看到refcount會繼續(xù)增加。然后unset掉b 和 $c 之后,refcount 恢復(fù)到了1,不過這時需要注意的是,is_ref 依然還是1,也就是說,這個變量被引用過,這個 is_ref 就會變成1,即使引用的變量都已經(jīng) unset 掉了這個值依然不變。

最后我們 unset 掉 $a ,顯示的就是 no such symbol 了。當(dāng)前變量已經(jīng)被銷毀不是一個可以用的符號引用了。(注意,PHP中的變量對應(yīng)的是內(nèi)存的符號表,并不是真正的內(nèi)存地址)

對象的引用計數(shù)

和普通類型的變量一樣,對象變量也是使用同樣的計數(shù)規(guī)則。

// 對象引用計數(shù)
class A{

}
$objA = new A();
xdebug_debug_zval('objA');
// objA: (refcount=1, is_ref=0)=class A {  }

$objB = $objA;
xdebug_debug_zval('objA');
// objA: (refcount=2, is_ref=0)=class A {  }

$objC = $objA;
xdebug_debug_zval('objA');
// objA: (refcount=3, is_ref=0)=class A {  }

unset($objB);
class C{

}
$objC = new C;
xdebug_debug_zval('objA');
// objA: (refcount=1, is_ref=0)=class A {  }

不過這里需要注意的是,對象的符號表是建立的連接,也就是說,對 objC 進(jìn)行重新實例化或者修改為 NULL ,并不會影響objC進(jìn)行重新實例化或者修改為NULL,并不會影響objA 的內(nèi)容,對象進(jìn)行普通賦值操作也是引用類型的符號表賦值,所以我們不需要加 & 符號。

數(shù)組的引用計數(shù)

// 數(shù)組引用計數(shù)
$arrA = [
    'a'=>1,
    'b'=>2,
];
xdebug_debug_zval('arrA');
// arrA: (refcount=2, is_ref=0)=array (
//     'a' => (refcount=0, is_ref=0)=1, 
//     'b' => (refcount=0, is_ref=0)=2
// )

$arrB = $arrA;
$arrC = $arrA;
xdebug_debug_zval('arrA');
// arrA: (refcount=4, is_ref=0)=array (
//     'a' => (refcount=0, is_ref=0)=1, 
//     'b' => (refcount=0, is_ref=0)=2
// )

unset($arrB);
$arrC = ['c'=>3];
xdebug_debug_zval('arrA');
// arrA: (refcount=2, is_ref=0)=array (
//     'a' => (refcount=0, is_ref=0)=1, 
//     'b' => (refcount=0, is_ref=0)=2
// )

// 添加一個已經(jīng)存在的元素
$arrA['c'] = &$arrA['a'];
xdebug_debug_zval('arrA');
// arrA: (refcount=1, is_ref=0)=array (
//     'a' => (refcount=2, is_ref=1)=1, 
//     'b' => (refcount=0, is_ref=0)=2, 
//     'c' => (refcount=2, is_ref=1)=1
// )

調(diào)試數(shù)組的時候,我們會發(fā)現(xiàn)兩個比較有意思的事情。

一是數(shù)組內(nèi)部的每個元素又有單獨(dú)的自己的引用計數(shù)。這也比較好理解,每一個數(shù)組元素都可以看做是一個單獨(dú)的變量,但數(shù)組就是這堆變量的一個哈希集合。如果在對象中有成員變量的話,也是一樣的效果。當(dāng)數(shù)組中的某一個元素被 & 引用賦值給其他變量之后,這個元素的 refcount 會增加,不會影響整個數(shù)組的 refcount 。

二是數(shù)組默認(rèn)上來的 refcount 是2。其實這是 PHP7 之后的一種新的特性,當(dāng)數(shù)組定義并初始化后,會將這個數(shù)組轉(zhuǎn)變成一個不可變數(shù)組(immutable array)。為了和普通數(shù)組區(qū)分開,這種數(shù)組的 refcount 是從2開始起步的。當(dāng)我們修改一下這個數(shù)組中的任何元素后,這個數(shù)組就會變回普通數(shù)組,也就是 refcount 會變回1。這個大家可以自己嘗試下,關(guān)于為什么要這樣做的問題,官方的解釋是為了效率,具體的原理可能還是需要深挖 PHP7 的源碼才能知曉。

關(guān)于內(nèi)存泄露需要注意的地方

其實 PHP 在底層已經(jīng)幫我們做好了 GC 機(jī)制就不需要太關(guān)心變量的銷毀釋放問題,但是,千萬要注意的是對象或數(shù)組中的元素是可以賦值為自身的,也就是說,給某個元素賦值一個自身的引用就變成了循環(huán)引用。那么這個對象就基本不太可能會被 GC 自動銷毀了。

// 對象循環(huán)引用
class D{
    public $d;
}
$d = new D;
$d->d = $d;
xdebug_debug_zval('d');
// d: (refcount=2, is_ref=0)=class D { 
//     public $d = (refcount=2, is_ref=0)=... 
// }

// 數(shù)組循環(huán)引用
$arrA['arrA'] = &$arrA;
xdebug_debug_zval('arrA');
// arrA: (refcount=2, is_ref=1)=array (
//     'a' => (refcount=0, is_ref=0)=1, 
//     'b' => (refcount=0, is_ref=0)=2, 
//     'arrA' => (refcount=2, is_ref=1)=...
// )

不管是對象還是數(shù)組,在打印調(diào)試時出現(xiàn)了 ... 這樣的省略號,那么你的程序中就出現(xiàn)了循環(huán)引用。所以這個問題應(yīng)該是我們在日常開發(fā)中應(yīng)該時刻關(guān)注的問題。

總結(jié)

引用計數(shù)是了解垃圾回收機(jī)制的前提條件,而且正是因為現(xiàn)代語言中都有一套類似的垃圾回收機(jī)制才讓我們的編程變得更加容易且安全。那么有人說了,日常開發(fā)根本用不到這些呀?用不到不代表不應(yīng)該去學(xué)習(xí),就像循環(huán)引用這個問題一樣,當(dāng)代碼中充斥著大量的類似代碼時,系統(tǒng)崩潰只是遲早的事情,所以,這些知識是我們向更高級的程序進(jìn)階所不可或缺的內(nèi)容。

測試代碼: github.com/zhangyue050…

以上就是詳解PHP的引用計數(shù)的詳細(xì)內(nèi)容,更多關(guān)于PHP的引用計數(shù)的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • PHP仿tp實現(xiàn)mvc框架基本設(shè)計思路與實現(xiàn)方法分析

    PHP仿tp實現(xiàn)mvc框架基本設(shè)計思路與實現(xiàn)方法分析

    這篇文章主要介紹了PHP仿tp實現(xiàn)mvc框架基本設(shè)計思路與實現(xiàn)方法,簡單講述了php實現(xiàn)tp框架的原理,并結(jié)合實例形式分析了相關(guān)控制器、視圖及URL訪問操作技巧與注意事項,需要的朋友可以參考下
    2018-05-05
  • PHP 5.3 下載時 VC9、VC6、Thread Safe、Non Thread Safe的區(qū)別分析

    PHP 5.3 下載時 VC9、VC6、Thread Safe、Non Thread Safe的區(qū)別分析

    我最近在 PHP 官網(wǎng)上看到又有新版的 PHP 下載了,于是上去找找 For Windows 的版本,可是一看確傻眼了
    2011-03-03
  • 詳解Laravel框架的依賴注入功能

    詳解Laravel框架的依賴注入功能

    依賴注入不是讓對象創(chuàng)建一個依賴關(guān)系,也不是讓工廠對象去創(chuàng)建對象,而是將所需的依賴變成一個外部對象,使之成為一個"某些人的問題”,你為"某些人的問題”注入了類的依賴關(guān)系。在Laravel中,這個"某人”是服務(wù)容器,服務(wù)容器負(fù)責(zé)通過構(gòu)造函數(shù)注入類的依賴關(guān)系。
    2021-05-05
  • PHP檢測用戶是否關(guān)閉瀏覽器的方法

    PHP檢測用戶是否關(guān)閉瀏覽器的方法

    這篇文章主要介紹了PHP檢測用戶是否關(guān)閉瀏覽器的方法,通過connection_status獲取連接狀態(tài)實現(xiàn)針對瀏覽器關(guān)閉的判定功能,需要的朋友可以參考下
    2016-02-02
  • php獲取excel文件數(shù)據(jù)

    php獲取excel文件數(shù)據(jù)

    本篇文章主要介紹了php獲取excel文件數(shù)據(jù)的方法。具有很好的參考價值。下面跟著小編一起來看下吧
    2017-04-04
  • php為字符串前后添加指定數(shù)量字符的方法

    php為字符串前后添加指定數(shù)量字符的方法

    這篇文章主要介紹了php為字符串前后添加指定數(shù)量字符的方法,涉及php操作字符串的相關(guān)技巧,非常具有實用價值,需要的朋友可以參考下
    2015-05-05
  • php 數(shù)組操作(增加,刪除,查詢,排序)等函數(shù)說明

    php 數(shù)組操作(增加,刪除,查詢,排序)等函數(shù)說明

    php 數(shù)組增加,刪除,查詢,排序詳細(xì)說明,需要的朋友可以參考下。
    2010-05-05
  • php中switch語句用法詳解

    php中switch語句用法詳解

    Switch語句也是面向?qū)ο缶幊陶Z句中最長常見的邏輯控制語句了。Switch 語句用于執(zhí)行基于多個不同條件的不同動作 – 即當(dāng)條件不同的時候,執(zhí)行不同的邏輯操作。
    2015-08-08
  • PHP substr 截取字符串出現(xiàn)亂碼問題解決方法[utf8與gb2312]

    PHP substr 截取字符串出現(xiàn)亂碼問題解決方法[utf8與gb2312]

    在PHP中,使substr函數(shù)截取字符串末位會出現(xiàn)亂碼,因為中文UTF-8編碼,每個漢字占3字節(jié),而GB2312占2字節(jié),英文占1字節(jié),截取位不準(zhǔn)確,造成斷開的字符會把其后的..拉過來一起做一個字,所以出現(xiàn)了亂碼。
    2011-12-12
  • PHP樹形結(jié)構(gòu)tree類用法示例

    PHP樹形結(jié)構(gòu)tree類用法示例

    這篇文章主要介紹了PHP樹形結(jié)構(gòu)tree類用法,結(jié)合實例形式分析了php無限分類樹tree.class.php的定義及使用相關(guān)操作技巧,需要的朋友可以參考下
    2019-02-02

最新評論