1. 程式人生 > 實用技巧 >PHP垃圾回收機制(GC)

PHP垃圾回收機制(GC)

PHP垃圾回收機制(GC)

前言

大多數程式語言都會有自身的垃圾回收機制,php也不例外。

在php5.3之前,是不包括垃圾回收機制的,也沒有專門的垃圾回收器,實現垃圾回收就是簡單判斷一下變數的zval的refcount是否為0,是的話就釋放。

但是如果這麼簡單的判斷垃圾回收的話,很容易引起程式過程中記憶體溢位。如果存在"自身指向自身"的情況的話,那麼變數將無法回收造成記憶體洩露,所以從php5.3開始就出現了專門負責清理垃圾資料防止記憶體洩露的垃圾回收器。

1、引用計數的基本知識

我們要了解GC,那麼首先要了解引起垃圾回收的計數是什麼。

在php中,每個變數存在一個叫“zval

”的變數容器中。一個zval變數容器,除了包含變數的型別和值,還包括另外兩個位元組的額外資訊:is_refrefcount

當一個變數被賦常量值時,就會生成一個zval變數容器。

1)is_ref

is_ref是個bool值,用來標識這個變數是否是屬於引用集合。通過這個位元組,php引擎才能把普通變數和引用變數區分開來。由於php允許使用者通過"&"來使用自定義的引用,所以zval中還有一個內部引用計數機制,來進行優化記憶體。

2)refcount

refcount用以表示指向這個zval變數容器的變數(也稱符號即symbol)的個數。所有符號存在一個符號表當中,每個符號都有作用域。

3)簡單來講:

refcount就是多少個變數是一樣的用了相同的值,那麼refcount就是這個值。

is_ref就是當有變數用了&的形式進行賦值,那麼is_ref的值就會增加1

2、環形引用

1)我們試一下,將陣列的引用賦值給陣列中的一個元素

 1 <?php
 2 $a = array( 'one' );
 3 $a[] =& $a;
 4 xdebug_debug_zval( 'a' );
 5 
 6 輸出:
 7 a: (refcount=2, is_ref=1)=array (
 8    0 => (refcount=1, is_ref=0)='one',
 9
1 => (refcount=2, is_ref=1)=... 10 ) 11 ?>

分析:這樣$a陣列就有兩個元素,一個索引為0,值為字元one,另外一個索引為1,為$a自身的引用。“…”表示1指向a自身,是一個環形引用

3、垃圾回收週期

在5.3之前的版本中,php無法處理迴圈的引用記憶體洩露。但是自5.3之後php使用引用計數系統中同步週期回收的同步演算法,僅處理這個記憶體洩露問題。

基本準則:

1)如果一個zval的refcount增加,那麼表明該變數的zval還在使用,不屬於垃圾

2)如果一個zval的refcount減少到0,那麼zval可以被釋放掉,可以清除,不是垃圾

3)如果在經過模擬刪除後一個zval的refcount減1,如果該zval的引用次數為是大於0,那麼此zval不能被釋放,可能是一個垃圾