91超碰碰碰碰久久久久久综合_超碰av人澡人澡人澡人澡人掠_国产黄大片在线观看画质优化_txt小说免费全本

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

如何在PHP7中實現垃圾回收機制

發布時間:2021-06-07 18:17:18 來源:億速云 閱讀:200 作者:Leah 欄目:開發技術

這篇文章給大家介紹如何在PHP7中實現垃圾回收機制,內容非常詳細,感興趣的小伙伴們可以參考借鑒,希望對大家能有所幫助。

垃圾回收機制

垃圾回收機制是一種動態存儲分配方案。它會自動釋放程序不再需要的已分配的內存塊。 自動回收內存的過程叫垃圾收集。垃圾回收機制可以讓程序員不必過分關心程序內存分配,從而將更多的精力投入到業務邏輯。 在現在的流行各種語言當中,垃圾回收機制是新一代語言所共有的特征。

垃圾的產生

PHP7 中復雜類型,像字符串、數組、對象等的數據結構中,頭部都有一個 gc, 這個 gc 的作用就是用來對垃圾回收的支持。當變量賦值、傳遞時,會增加 value 的引用數, unset、return 等釋放變量時再減掉引用數,減掉后如果發現 refcount 變為 0 則直接釋放 value,這是變量的基本回收過程。

不過有一種問題是這個機制無法解決的,就是循環引用的問題。

什么是循環引用呢? 簡單說就是變量的內部里存的 value 又引用了變量自身。 這種比較經常發生在數組和對象類型的變量上。

這里先講一下引用,即 zend_reference 這個類型,這個是 PHP7 新增的變量類型,當對變量使用 “&” 操作時,會創建新的中間結構體 zend_reference,這個結構體會真正的指向對應的 value 結構。

舉個例子:

// 當進行如下賦值操作時
$a = 'hello'; // $a -> zend_string
$b = $a; // $b,$a -> zend_string
$c = &$b; // $c,$b -> zval(type = IS_REFERENCE, refcount = 2) -> zend_string

最終會變成如下這樣:

 如何在PHP7中實現垃圾回收機制

即 $b 和 $c 的 zval 是通過中間結構體 zend_reference 再指向最終的 zend_string

回到循環引用的問題,舉個數組循環引用例子:

$arr = [1];
$a[] = &$a;
unset($a);

使用 & 操作之后,變量 a 就變成了引用類型且引用計數 refcount 為 2,而又賦值給自己里面的元素,即變量 a 變成了自己引用自己。

具體如下如所示:

 如何在PHP7中實現垃圾回收機制

當 unset 之后就變成下圖這樣:

 如何在PHP7中實現垃圾回收機制

即 $a 所在的 zval 類型已經變成了 IS_UNDEF 了,zend_reference 結構體的引用計數減 1,但是仍然大于 0,這時候,這部分結構體就變成了垃圾,對此不處理的話,就可能會造成內存泄露。這里就需要垃圾收集器將這部分收集到緩沖區,之后進行回收處理。

回收過程

如果當變量的 refcount 減小后大于 0,PHP 并不會立即對這個變量進行垃圾鑒定和回收,而是放入一個緩沖區中,等這個緩沖區滿了以后(10000 個值)再統一進行處理,加入緩沖區的是變量 zend_value 里的 gc,目前垃圾只會出現在數組和對象兩種類型中,數組的情況上面已經介紹了,對象的情況則是成員屬性引用對象本身導致的,其它類型不會出現這種變量中的成員引用變量自身的情況,所以垃圾回收只會處理這兩種類型的變量。

gc 的結構 zend_refcounted_h 具體如下:

typedef struct _zend_refcounted_h {
  uint32_t     refcount; // 記錄 zend_value 的引用數
  union {
    struct {
      zend_uchar  type, // zend_value的類型, 與zval.u1.type一致
      zend_uchar  flags, 
      uint16_t   gc_info // GC信息,記錄在 gc 池中的位置和顏色,垃圾回收的過程會用到
    } v;
    uint32_t type_info;
  } u;
} zend_refcounted_h;

一個變量只能加入一次緩沖區,為了防止重復加入,變量加入后會把 zend_refcounted_h.gc_info 置為 GC_PURPLE,即標為紫色,后續不會重復插入。

垃圾緩沖區是一個雙向鏈表,等到緩存區滿了以后則啟動垃圾檢查過程:遍歷緩沖區,對當前變量的所有成員進行遍歷,然后把成員的 refcount 減 1 (如果成員還包含子成員則也進行遞歸遍歷,即深度優先遍歷),最后再檢查當前變量的引用,如果減為了 0 則為垃圾。這個算法的原理核心是:垃圾是由于成員引用自身導致的,那么就對所有的成員減一遍引用,如果發現最后變量本身的 refcount 變為了 0 則就表明其引用全部來自自身成員,即其他任何地方都不再使用它,那么它就是垃圾,需要被回收掉。反之說明不是垃圾,需要將其從緩沖區移出去。具體的過程如下:

(1) 從緩沖區鏈表的 roots 開始遍歷,把當前 value 標為灰色 (zend_refcounted_h.gc_info 置為 GC_GREY),然后對當前 value 的成員進行深度優先遍歷,把成員 value 的 refcount 減 1,并且也標為灰色;

(2) 重復遍歷緩沖區鏈表,檢查當前 value 引用是否為 0,為 0 則表示確實是垃圾,把它標為白色(GC_WHITE),如果不為 0 則排除了引用全部來自自身成員的可能,表示還有外部的引用,并不是垃圾,這時候因為步驟(1)對成員進行了 refcount 減 1 操作,需要再還原回去,對所有成員進行深度遍歷,把成員 refcount 加 1,同時標為黑色;

(3) 再次遍歷緩沖區鏈表,將非 GC_WHITE 的節點從 roots 鏈表中移出(移到待釋放的列表),最終 roots 鏈表中全部為真正的垃圾,最后將這些垃圾清除。

關于如何在PHP7中實現垃圾回收機制就分享到這里了,希望以上內容可以對大家有一定的幫助,可以學到更多知識。如果覺得文章不錯,可以把它分享出去讓更多的人看到。

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

php
AI

饶河县| 新巴尔虎左旗| 察雅县| 都江堰市| 衡阳市| 霞浦县| 灌南县| 汾阳市| 漳平市| 太仆寺旗| 北碚区| 两当县| 三穗县| 肃南| 镇原县| 安溪县| 全椒县| 莱西市| 临沭县| 黄平县| 罗江县| 庆阳市| 个旧市| 城固县| 宜城市| 兴山县| 西丰县| 滦南县| 蓬溪县| 利辛县| 平利县| 茂名市| 壶关县| 博罗县| 汪清县| 叙永县| 东丰县| 原阳县| 高陵县| 铜山县| 南溪县|