目錄
zval 的結構
循環引用造成的記憶體洩漏
object和array的回收過程
垃圾回收的原理
例子
首頁 後端開發 PHP7 php7如何實現垃圾回收機制

php7如何實現垃圾回收機制

May 24, 2021 am 09:21 AM
php7 垃圾回收機制

這篇文章要為大家介紹一下php7實作垃圾回收機制的方法。有一定的參考價值,有需要的朋友可以參考一下,希望對大家有幫助。

php7如何實現垃圾回收機制

在了解我們 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<
登入後複製

unset($ a) 之後,就變成這樣

這時候,我們unset操作時refcount 由2變為1,因為有內部引用指向$a,所以在外部其所佔用的空間並不會被銷毀。

然後我們的外部引用已經被中斷了,我們也不能使用它。它就成了一個“孤兒”,在c語言中叫做野指針。在php中叫做循環引用。內存洩漏。想要銷毀變數的話,只能等 php腳本結束。

循環引用造成的記憶體洩漏

為了清理這些垃圾,引入了兩個準則

  • 如果引用計數減少到零,所在變數容器將被清除(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 
模拟减结束,那么此变量被当成垃圾回收。
登入後複製

推薦學習:php影片教學

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

本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡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脫衣器

AI Hentai Generator

AI Hentai Generator

免費產生 AI 無盡。

熱門文章

R.E.P.O.能量晶體解釋及其做什麼(黃色晶體)
1 個月前 By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.最佳圖形設置
1 個月前 By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.如果您聽不到任何人,如何修復音頻
1 個月前 By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.聊天命令以及如何使用它們
1 個月前 By 尊渡假赌尊渡假赌尊渡假赌

熱工具

記事本++7.3.1

記事本++7.3.1

好用且免費的程式碼編輯器

SublimeText3漢化版

SublimeText3漢化版

中文版,非常好用

禪工作室 13.0.1

禪工作室 13.0.1

強大的PHP整合開發環境

Dreamweaver CS6

Dreamweaver CS6

視覺化網頁開發工具

SublimeText3 Mac版

SublimeText3 Mac版

神級程式碼編輯軟體(SublimeText3)

php7.0怎麼安裝mongo擴展 php7.0怎麼安裝mongo擴展 Nov 21, 2022 am 10:25 AM

php7.0安裝mongo擴充的方法:1、建立mongodb使用者群組和使用者;2、下載mongodb原始碼包,並將原始碼包放到“/usr/local/src/”目錄下;3、進入“src/”目錄;4、解壓縮原始碼包;5、建立mongodb檔案目錄;6、將檔案複製到「mongodb/」目錄;7、建立mongodb設定檔並修改設定即可。

php7檢測tcp埠不好用怎麼解決 php7檢測tcp埠不好用怎麼解決 Mar 22, 2023 am 09:30 AM

在php5中,我們可以使用fsockopen()函數來偵測TCP埠。這個函數可以用來開啟一個網路連接和進行一些網路通訊。但是在php7中,fsockopen()函數可能會遇到一些問題,例如無法開啟連接埠、無法連接到伺服器等。為了解決這個問題,我們可以使用socket_create()函數和socket_connect()函數來偵測TCP埠。

php7.0安裝了插件還是顯示未安裝怎麼辦 php7.0安裝了插件還是顯示未安裝怎麼辦 Apr 02, 2024 pm 07:39 PM

解決 PHP 7.0 中插件未顯示已安裝問題的方法:檢查插件配置並啟用插件。重新啟動 PHP 以套用配置變更。檢查插件檔案權限,確保其正確。安裝遺失的依賴項,以確保插件正常運作。如果其他步驟都失敗,則重建 PHP。其他可能原因包括外掛程式版本不相容、載入錯誤版本或 PHP 配置問題。

一文聊聊php中的垃圾回收機制 一文聊聊php中的垃圾回收機制 Aug 26, 2022 am 10:48 AM

這篇文章帶大家深入了解php中的垃圾回收機制,希望對大家有幫助!

PHP 伺服器環境常見問題指南:快速解決常見難題 PHP 伺服器環境常見問題指南:快速解決常見難題 Apr 09, 2024 pm 01:33 PM

PHP伺服器環境常見的解決方法包括:確保已安裝正確的PHP版本和已複製相關檔案到模組目錄。暫時或永久停用SELinux。檢查並配置PHP.ini,確保已新增必要的擴充功能和進行正確設定。啟動或重新啟動PHP-FPM服務。檢查DNS設定是否有解析問題。

php7.0怎麼安裝部署 php7.0怎麼安裝部署 Nov 30, 2022 am 09:56 AM

php7.0安裝部署的方法:1、到PHP官網下載與本機系統對應的安裝版本;2、將下載的zip檔案解壓縮到指定目錄;3、開啟命令列窗口,在「E:\php7」目錄下運行“php -v”命令即可。

如何在系統重啟後自動設置unixsocket的權限? 如何在系統重啟後自動設置unixsocket的權限? Mar 31, 2025 pm 11:54 PM

如何在系統重啟後自動設置unixsocket的權限每次系統重啟後,我們都需要執行以下命令來修改unixsocket的權限:sudo...

解密Go語言的記憶體管理與垃圾回收機制 解密Go語言的記憶體管理與垃圾回收機制 Nov 30, 2023 am 09:17 AM

Go語言是一門高效、安全、並發的程式語言,其中記憶體管理和垃圾回收機制的設計也是其獨特之處。本文將深入解密Go語言的記憶體管理與垃圾回收機制。一、記憶體管理在Go語言中,記憶體管理包括記憶體分配和記憶體釋放兩個面向。 1.1記憶體分配在Go語言中,我們透過內建函數new和make來進行記憶體分配。其中,new傳回指向新指派的零值的指針,而make則傳回指定型別及其長

See all articles