PHP5.2版本的記憶體回收機制主要針對zval結構中的refcount=0時釋放變數,但複合類型的數組或對象,環形引用或者引用自己,都是造成記憶體泄露,PHP官網的介紹5.3的GC機制,通過將zval放入root buffer,進行類比刪除(refcount-1),當refcount==0時被認為是垃圾,而回收,下面是4個步驟:
例如:
這樣$a數組就有兩個元素,一個索引為0,值為字元one,另外一個索引為1,為$a自身的引用,內部儲存如下:
a: (refcount=2, is_ref=1)=array (
0 => (refcount=1, is_ref=0)='one',
1 => (refcount=2, is_ref=1)=...
)
“...”表示1指向a自身,是一個環形引用:
按照網上表達所說:先放入root buffer中,refcount-1,這時$a的refcount=1,然後unset一下,refcount=0,則認為$a為垃圾
問題:
1. 我現在假設$a數組中,有2個key引用了自己,比如:
a: (refcount=3, is_ref=1)=array (
0 => (refcount=1, is_ref=0)='one',
1 => (refcount=3, is_ref=1)=...
2 => (refcount=3, is_ref=1)=...
)
那麼該數組進行unset後肯定是個垃圾,那麼比如我先放到buffer, refcount-1,那麼refcount=2,然後再unset-1,refcount=1,這樣似乎雖然這個數組刪除時會造成垃圾,但根據新的GC的機制說,只有當refcount=0時才會被認為是垃圾,那不是矛盾了嗎? 那我數組裡面是不是只要>=2的key引用了本身,都不會視為垃圾了?
回複內容:
PHP5.2版本的記憶體回收機制主要針對zval結構中的refcount=0時釋放變數,但複合類型的數組或對象,環形引用或者引用自己,都是造成記憶體泄露,PHP官網的介紹5.3的GC機制,通過將zval放入root buffer,進行類比刪除(refcount-1),當refcount==0時被認為是垃圾,而回收,下面是4個步驟:
例如:
這樣$a數組就有兩個元素,一個索引為0,值為字元one,另外一個索引為1,為$a自身的引用,內部儲存如下:
a: (refcount=2, is_ref=1)=array (
0 => (refcount=1, is_ref=0)='one',
1 => (refcount=2, is_ref=1)=...
)
“...”表示1指向a自身,是一個環形引用:
按照網上表達所說:先放入root buffer中,refcount-1,這時$a的refcount=1,然後unset一下,refcount=0,則認為$a為垃圾
問題:
1. 我現在假設$a數組中,有2個key引用了自己,比如:
a: (refcount=3, is_ref=1)=array (
0 => (refcount=1, is_ref=0)='one',
1 => (refcount=3, is_ref=1)=...
2 => (refcount=3, is_ref=1)=...
)
那麼該數組進行unset後肯定是個垃圾,那麼比如我先放到buffer, refcount-1,那麼refcount=2,然後再unset-1,refcount=1,這樣似乎雖然這個數組刪除時會造成垃圾,但根據新的GC的機制說,只有當refcount=0時才會被認為是垃圾,那不是矛盾了嗎? 那我數組裡面是不是只要>=2的key引用了本身,都不會視為垃圾了?
找到答案了嗎?我嘗試回答下
按照樓主說的,看看下面的內容:
$a = 123;$b = $a; //a: (refcount=2, is_ref=0)=123 b: (refcount=2, is_ref=0)=123unset($b); //a: (refcount=1, is_ref=0)=123
此時a所指向的zval也會進入垃圾周期,然後對refcount減一,是不是符號a指向的zval也要刪除了?顯然不是
這雷根據我所瞭解的說說我的看法:GC不會對可能的垃圾根項目進行減一操作,而是會對根項目下面的元素進行減一操作,這樣解釋才合理。
就說說你這種情況,根節點zval計數不會進行減一操作,循環參考的時候,對循環參考指向的zval計數進行減一,這樣不管多少循環參考都可以減到0,這樣是不是可以說的通了。
仔細看圖你沒發現問題嗎?明明產生了一個自引用,但是為什麼refcount還是1呢?應該是變數釋放到buffer裡面然後refcount--的原因。你就是這塊沒理解對。