搜尋
首頁後端開發PHP7閒聊 php7 垃圾回收機制

閒聊 php7 垃圾回收機制

Jan 08, 2021 am 09:50 AM
php7垃圾回收機制

PHP7專欄介紹垃圾回收機制

閒聊 php7 垃圾回收機制

推薦(免費): PHP7

文章目錄

  • zval 的結構
  • 迴圈引用造成的記憶體洩漏
  • object和array的回收過程
    • #垃圾回收的原理
    • 範例

在了解我們php GC 時,我覺得我有必要介紹一下們的php 的變數在底層的實作。

zval 的結構

// php 变量对于的c结构体
struct _zval_struct {
    zend_value value;
    union {
       ……
    } u1;
    union {
        ……
    } u2;
};

由於主要講垃圾回收,所以在這裡簡單介紹下u1 u2 聯合體的功能
u1結構比較複雜,我認為主要是用來識別變數類型
u2 這裡面大多都是輔助字段,變數內部功能的實作、提升快取友善等
接下來是我們的主角

zend_value 它也是結構體中內嵌的一個聯合體

typedef union _zend_value {
    zend_long         lval;//整形
    double            dval;//浮点型
    zend_refcounted  *counted;//获取不同类型的gc头部
    zend_string      *str;//string字符串
    zend_array       *arr;//数组
    zend_object      *obj;//对象
    zend_resource    *res;//资源
    zend_reference   *ref;//是否是引用类型
  
    // 忽略下面的结构,与我们讨论无关
    zend_ast_ref     *ast;
    zval             *zv;
    void             *ptr;
    zend_class_entry *ce;
    zend_function    *func;
    struct {
        ZEND_ENDIAN_LOHI(
            uint32_t w1,
            uint32_t w2)
    } ww;
} zend_value;

zval的value中就記錄了引用計數zend_refcounted *counted這個類型,我們的垃圾回收機制也是基於此的。

typedef struct _zend_refcounted_h {
    uint32_t         refcount;          /* reference counter 32-bit */
    union {
        struct {
            ZEND_ENDIAN_LOHI_3(
                zend_uchar    type,
                zend_uchar    flags,    /* used for strings & objects */
                uint16_t      gc_info)  /* keeps GC root number (or 0) and color */
        } v;
        uint32_t type_info;
    } u;
} zend_refcounted_h;

所有的複雜類型的定義, 開始的時候都是zend_refcounted_h結構, 這個結構裡除了引用計數以外, 還有GC相關的結構. 從而在做GC回收的時候, GC不需要關心具體類型是什麼, 所有的它都可以當做zend_refcounted*結構來處理.
#變數的自動回收

在php中除了array object類型的變量,其餘大部分是自動回收
php 普通變數的回收和該變數的引用次數有關。

官方的例子

$a = 1;
$b = $a;
xdebug_debug_zval('a');
$a =10;
xdebug_debug_zval('a');
unset($a);
xdebug_debug_zval('a');

結果

a:
(refcount=2, is_ref=0),int 1
a:
(refcount=1, is_ref=0),int 10
a: no such symbol

可以看到當$a =10 的時候涉及到php的COW(copy-on- write)機制,$b 會複製一份原先的$a ,解除了他們之間的引用關係,所以a的引用次數(refcount)減少為1。

然後我們uset($a)之後 a的引用次數變成0。這就會被認為是垃圾變量,釋放空間。

在舉例

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

在unset($a) 之前$a 的型別為引用型別

a:
(refcount=2, is_ref=1),
array (size=2)
  0 => (refcount=1, is_ref=0),int 1
  1 => (refcount=2, is_ref=1),
    &array<p><img src="/static/imghwm/default1.png" data-src="https://img.php.cn/upload/article/000/000/052/163e22c0271ab639b6a5080b1ccd0d58-0.jpg?x-oss-process=image/resize,p_40" class="lazy" alt=""></p><p>unset($ a) 之後,就變成這樣</p><p><img src="/static/imghwm/default1.png" data-src="https://img.php.cn/upload/article/000/000/052/163e22c0271ab639b6a5080b1ccd0d58-1.jpg?x-oss-process=image/resize,p_40" class="lazy" alt=""></p><p>這時候,我們<code>unset</code>操作時refcount 由2變成1,因為有內部引用指向$a ,所以在外部其所佔用的空間並不會被銷毀。 </p><p>然後我們的外部引用已經被中斷了,我們也不能使用它。它就成了一個“孤兒”,在c語言中叫做野指針。在php中叫做循環引用。內存洩漏。想要銷毀變數的話,只能等 php腳本結束。 </p><p><strong>循環引用造成的記憶體洩漏</strong></p><p>為了清理這些垃圾,引入了兩個準則</p>
  • 如果引用計數減少到零,所在變數容器將被清除(free),不屬於垃圾
  • 如果一個zval 的參考計數減少後還大於0,那麼它會進入垃圾週期。其次,在一個垃圾週期中,透過檢查引用計數是否減1,並且檢查哪些變數容器的引用次數是零,來發現哪一部分是垃圾。

循環引用基本上只會出現在陣列和物件中,物件是因為它的本身就是引用

object和array的回收過程

php7的垃圾回收包含兩個部分,一個是垃圾收集器,一個是垃圾回收演算法。

垃圾收集器,把剛剛提到的,可能是垃圾的元素收集到回收池中 也就是把變數的 zend_refcount>0的變數 放在回收池中。當回收池的值達到一定額度了,會進行統一遍歷處理。進行模擬刪除,如果zend_refcount=0那就認為是垃圾,直接刪除它。

遍歷回收池中的每一個變量,根據每一個變量,再遍歷每一個成員,如果成員還有嵌套的話繼續遍歷。然後把所有成員的 做模擬的 refcount -1。若此時外部的變數的 引用次數為 0 。那麼可以視為垃圾,清楚。如果大於0,那麼恢復引用次數,並從垃圾回收池中取出。

垃圾回收的原理

如果你這個變數不是垃圾,那麼它的所有成員變數的引用減一之後,必然不會是總變數的引用為0。

例子

說的比較死,不如舉例。剛刷 sf.gg 的時候看到一個關於 GC 的題,我回答了一波。關於GC垃圾回收機制

題目如下
閒聊 php7 垃圾回收機制

#
//我的回答
1、只要zval.value的refcount减一,然后缺其refcount的值不为0那么它就可能是垃圾,进入垃圾周期。
2、进入垃圾池遍历所有成员,包括其嵌套的成员,都对其做 refcount-1的操作,看外部的引用是否为0。

那么对于 题主的问题来说,
首先,你要想$a为垃圾,一定要先对 unset($a)操作,那么此时 $a的 refcount = 2
对于$a[0] refcount-1 不影响外部的$a,
$a[1] refcount-1 ,此时 $a的 refount=1
$a[2] refcount-1 ,此时 $a 的 refount=0 
模拟减结束,那么此变量被当成垃圾回收。

更多编程相关知识,请访问:编程教学!!

以上是閒聊 php7 垃圾回收機制的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述
本文轉載於:CSDN。如有侵權,請聯絡admin@php.cn刪除

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

Video Face Swap

Video Face Swap

使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱工具

Dreamweaver Mac版

Dreamweaver Mac版

視覺化網頁開發工具

SecLists

SecLists

SecLists是最終安全測試人員的伙伴。它是一個包含各種類型清單的集合,這些清單在安全評估過程中經常使用,而且都在一個地方。 SecLists透過方便地提供安全測試人員可能需要的所有列表,幫助提高安全測試的效率和生產力。清單類型包括使用者名稱、密碼、URL、模糊測試有效載荷、敏感資料模式、Web shell等等。測試人員只需將此儲存庫拉到新的測試機上,他就可以存取所需的每種類型的清單。

mPDF

mPDF

mPDF是一個PHP庫,可以從UTF-8編碼的HTML產生PDF檔案。原作者Ian Back編寫mPDF以從他的網站上「即時」輸出PDF文件,並處理不同的語言。與原始腳本如HTML2FPDF相比,它的速度較慢,並且在使用Unicode字體時產生的檔案較大,但支援CSS樣式等,並進行了大量增強。支援幾乎所有語言,包括RTL(阿拉伯語和希伯來語)和CJK(中日韓)。支援嵌套的區塊級元素(如P、DIV),

SublimeText3 英文版

SublimeText3 英文版

推薦:為Win版本,支援程式碼提示!

VSCode Windows 64位元 下載

VSCode Windows 64位元 下載

微軟推出的免費、功能強大的一款IDE編輯器