PHP是一種弱類型的腳本語言,弱類型不表示PHP變量沒有類型的區別,PHP變量有8種原始類型:
四種標量類型:php
兩種複合類型:程序員
兩種特殊類型:算法
在引擎內部,變量都是用一個結構體來表示的。這個結構體能夠在{PHPSRC}/Zend/zend.h中找到:編程
struct _zval_struct { /* Variable information */ zvalue_value value; /* value */ zend_uint refcount__gc; //表明一個計數器,表示有多少個變量名指向這個zval容器 zend_uchar type; /* active type */ zend_uchar is_ref__gc; //此字段是一個布爾值,用來標識變量是不是一個引用,經過這個字段,PHP引擎能夠區分通常變量和引用變量 };
父進程fork子進程以後,子進程的地址空間仍是簡單的指向父進程的地址空間,只有當子進程須要寫地址空間中的內容的時候,纔會單獨分離一份給子進程,這樣就算子進程立刻調用exec函數也沒有關係,由於根本就不須要從父進程的地址空間中拷貝內容,這樣就節省了內存同時又提升了速度。這個邏輯能夠敘述爲:對一個通常變量a(isref=0)進行通常的賦值操做,若是a所指向的zval的計數refcount大於1,那麼須要爲a從新分配一個新的zval,而且把以前的zval的計數refcount減小1。數組
幾個基本準則:函數
新的GC算法目的就是防止循環引用的變量引發內存泄露問題。在PHP中GC算法,當節點緩衝區滿了以後,垃圾分析算法就會啓動,而且會釋放掉髮現的垃圾,從而回收內存。ui
如今,若是咱們試一下,將數組的引用賦值給數組中的一個元素,有意思的事情發生了:spa
<?php $a = array("one"); $a[] = &$a; ?>
這樣$a數組就有兩個元素,一個索引爲0,值爲字符one,另外一個索引爲1,爲$a自身的引用,內部存儲以下:3d
a: (refcount=2, is_ref=1)=array ( 0 => (refcount=1, is_ref=0)='one', 1 => (refcount=2, is_ref=1)=... )
「...」表示1指向a自身,是一個環形引用(循環引用):
code
這個時候咱們對$a進行unset,那麼$a會從符號表中刪除,同時$a指向的zval的refcount減小1。
<?php $a = array('one'); $a[] = &$a; unset($a); ?>
那麼問題產生了,$a已經再也不符號表中了,用戶沒法再訪問此變量,可是$a以前指向的zval的refcount變爲1而不是0,所以不能被回收,這樣產生了內存泄露:
這樣zval就成爲一個垃圾了,新的GC要作的工做就是清理這種垃圾。
在PHP編程中程序員不須要手動處理內存資源分配與釋放,意味着PHP自己實現了垃圾回收處理機制。
這個算法叫作「引用計數」,其思想很是直觀和簡潔:爲每一個內存對象分配一個計數器,當一個內存對象創建時計數器初始化爲1(所以此時老是有一個變量引用此對象),之後每有一個新變量引用此內存對象,則計數器加1,而每當減小一個引用此內存對象的變量則計數器減1,當垃圾回收機制運做時,將全部計數器爲0的內存對象銷燬並回收其佔用的內存。而php中內存對象就是zval,而計數器就是refcount__gc。