您好,登錄后才能下訂單哦!
本篇內容主要講解“PHP的垃圾回收機制相關知識點整理”,感興趣的朋友不妨來看看。本文介紹的方法操作簡單快捷,實用性強。下面就讓小編來帶大家學習“PHP的垃圾回收機制相關知識點整理”吧!
PHP目前的開發框架,除了主流常用的FPM框架,想必就是基于swoole拓展的常駐內存開發了。
我們在FPM的開發模式中,每一次腳本程序結束之后,所有變量都會被銷毀,內存會被釋放,所以我們不用太擔心。
但是常駐內存開發模式就不一樣了,如果不注意變量內存的使用,無法很好的管理內存問題,會造成內存泄露。
所以,我們一定要熟悉PHP的垃圾回收機制(Garbage Collector 簡稱GC)
在PHP7+版本中,有關于變量內存的操作特性,采用了寫時復制,也就是說, 在必要的時候才會進行深拷貝(即發生寫的時候才會進行深拷貝).
當變量值為interned string字符串型(變量名,函數名,靜態字符串,類名等)時,變量值存儲在靜態區,內存回收被系統全局接管,引用計數將一直為1 。
當賦值變量的值為 整型,浮點型 時,php7底層將會直接把值存儲(php7的結構體將會直接存儲簡單數據類型),refcount將為0,我們用代碼來看一下:
$a = 'chris'.time();$b = $a; //此時$b指向$a的同一個內存地址$c = $a; //一樣xdebug_debug_zval('a');//a:(refcount=3, is_ref=0)string 'chris1614780053' (length=15)我們通過Xdebug來觀察變量的信息,他們指的都是同一個內存地址,是引用。
$a = 'chris'.time();$b = '青玄';$c = $a;xdebug_debug_zval('a');xdebug_debug_zval('b');//a:(refcount=2, is_ref=0)string 'chris1614780283' (length=15) //b:(interned, is_ref=0)string '青玄' (length=6) //存在了靜態區我們通過Xdebug來觀察變量的信息,這時$b的值已經發生了變化,這時候,才會使用新的內存空間,$a的引用次數-1。
每個php變量存在一個叫”zval”的變量容器中。一個zval變量容器,除了包含變量的類型和值,還包括兩個字節的額外信息。第一個是”is_ref”,是個bool值,用來標識這個變量是否是屬于引用集合(reference set)。通過這個字節,php引擎才能把普通變量和引用變量區分開來,由于php允許用戶通過使用&來使用自定義引用,zval變量容器中還有一個內部引用計數機制,來優化內存使用。第二個額外字節是”refcount”,用以表示指向這個zval變量容器的變量(也稱符號即symbol)個數。
官方文檔的描述
簡單來說,就是給變量引用的次數進行計算,當計數refcount不等于0時,說明這個變量已經被引用,不能直接被回收,否則可以直接回收,用代碼來看看把
$a='chris'.time();$b=$a;$c=$a; $b='青玄';unset($c);xdebug_debug_zval('a');//a:(refcount=1, is_ref=0)string 'chris1614780526'(length=5)//我們可以看到,刪除$c,并不能把$a刪除,因為refcount=1
function a(){class A { public $ref; public $name; public function __construct($name) { $this->name = $name; echo($this->name.'->__construct();'.PHP_EOL); } public function __destruct() { echo($this->name.'->__destruct();'.PHP_EOL); }}$a1 = new A('$a1');$a2 = new A('$a2');$a3 = new A('$3');$a1->ref = $a2;$a2->ref = $a1;unset($a1);unset($a2);echo('exit(1);'.PHP_EOL);}a();echo('exit(2);'.PHP_EOL);
當$a1和$a2的屬性互相引用時,unset($a1,$a2) 只能刪除變量的引用,卻沒有真正的刪除類的變量,這是為什么呢?
首先,類的實例化變量分為2個步驟
1:開辟類存儲空間,用于存儲類數據
2:實例化一個變量,類型為class,值指向類存儲空間
當給變量賦值成功后,類的引用計數為1,同時,a1->ref指向了a2,導致a2類引用計數增加1,同時a1類被a2->ref引用,a1引用計數增加1
當unset時,只會刪除類的變量引用,也就是-1,但是該類其實還存在了一次引用(類的互相引用),
這將造成這2個類內存永遠無法釋放,直到被gc機制循環查找回收,或腳本終止回收(域結束無法回收).
每個方法/函數都作為一個作用域,當運行完該作用域時,將會回收作用域內的所有變量,全局變量只有在腳本結束后才會回收。
我們可以通過以下方式來手動回收:
unset() : unset的回收原理其實就是引用計數-1,當引用計數-1之后為0時,將會直接回收該變量,否則不做操作(這就是上面內存泄漏的原因,引用計數-1并沒有等于0)。
賦值為null :=null和unset($a),作用其實都為一致,null將變量值賦值為null,原先的變量值引用計數-1,而unset是將變量名從php底層變量表中清理,并將變量值引用計數-1,唯一的區別在于,=null,變量名還存在,而unset之后,該變量就沒了。
變量覆蓋回收:通過給變量賦值其他值(例如null)進行回收,但是從程序的內存占用來說,覆蓋變量并不是意義上的內存回收,只是將變量的內存修改為了其他值.內存不會直接清空。
gc_collect_cycles :強制執行周期回收,在PHP執行中,一旦根緩沖區滿了或者調用gc_collect_cycles() 函數時,就會執行垃圾回收
另外:為避免不得不檢查所有引用計數可能減少的垃圾周期,PHP會有算法把疑似垃圾的變量,放在根緩沖區(root buffer)中,在根緩沖區滿了的時候,也會對垃圾緩沖區進行一次回收。
到此,相信大家對“PHP的垃圾回收機制相關知識點整理”有了更深的了解,不妨來實際操作一番吧!這里是億速云網站,更多相關內容可以進入相關頻道進行查詢,關注我們,繼續學習!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。