這兩個東西長得很像,起初我還錯誤以為一個是針對zval一個針對zval*的釋放函數,唉,太天真了。這兩個函數都與zval的釋放有關,是我們肯定會經常碰到的兩個函數。
下面是兩者的聲明:
//zval_dtor是宏函數,最終展開後
ZEND_API void _zval_dtor_func(zval *zvalue ZEND_FILE_LINE_DC)
//zval_ptr_dtor是宏函數,最終展開後
ZEND_API void _zval_ptr_dtor(zval **zval_ptr ZEND_FILE_LINE_DC)
兩者的工作都與釋放zval有關,但又有很大的區別。
比如我們有一個zval *tmp,而且我們已經對它進行了MAKE_STD_ZVAL等一系列操作了。
如果我們對它使用zval_dtor會發生什麼事情呢?
zval_dtor會直接把我們的tmp的value部分即tmp->value所指的記憶體釋放掉。當然也可能不是直接釋放掉,而是重新交給ZendMM,由ZendMM進行重新分配或者釋放。
如果我們對它使用zval_ptr_dtor會發生什麼事情呢?
zval_ptr_dtor首先會將它的refcount減一,如果減一後refcount為0了,便會再調用zval_dtor把tmp->value給釋放掉,然後再調用efree_rel()函數把自己tmp所指的zval類型結構體所佔的記憶體空間給釋放掉。
如果減一後不為0呢?那zval_ptr_dtor便不會釋放tmp->value和tmp本身,而是通知一下GC記憶體回收行程,然後返回而已。這裡你可能要問了,它通知GC記憶體回收行程幹嘛,難道有基情?這個具體的細節我也說不清楚,只能從功能上來描述一下。
PHP文檔中有這麼一句話:”首先,我們先要建立一些基本規則,如果一個引用計數增加,它將繼續被使用,當然就不再在垃圾中。如果引用計數減少到零,所在變數容器將被清除(free)。就是說,僅僅在引用計數減少到非零值時,才會產生垃圾周期(garbage cycle)。其次,在一個垃圾周期中,通過檢查引用計數是否減1,並且檢查哪些變數容器的引用次數是零,來發現哪部分是垃圾。”.
引用計數減少到零的時候,zval_ptr_dtor便會調用zval_dtor與efree_rel將tmp->value與tmp本身都徹底真正的釋放掉了,所以不會有什麼問題。但是如果減1後不為0,便會產生一個垃圾周期。每10000[寫入程式碼在源碼裡的一個值]個垃圾周期便會啟用一次真正的記憶體回收機制。增加這一步的原因是因為以前php用到的引用計數記憶體機制,無法處理迴圈的引用記憶體流失。
關於這個機制的核心演算法是一個27頁的pdf文檔,:http://www.research.ibm.com/people/d/dfb/papers/Bacon01Concurrent.pdf。
轉載自:
http://walu.sinaapp.com/?p=129
結論是什麼呢?
當我們不再需要tmp的時候,應該使用zval_ptr_dtor(&tmp);