PHP垃圾回收機制

PHP是一種弱類型的腳本語言,弱類型不表示PHP變量沒有類型的區別,PHP變量有8種原始類型:
四種標量類型:php

  • boolean(布爾值)
  • integer(整型)
  • float(浮點型)

兩種複合類型:程序員

  • array(數組)
  • object(對象)

兩種特殊類型:算法

  • resource(資源)
  • NULL

在引擎內部,變量都是用一個結構體來表示的。這個結構體能夠在{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引擎能夠區分通常變量和引用變量
   };

copy on write(寫時複製技術)

父進程fork子進程以後,子進程的地址空間仍是簡單的指向父進程的地址空間,只有當子進程須要寫地址空間中的內容的時候,纔會單獨分離一份給子進程,這樣就算子進程立刻調用exec函數也沒有關係,由於根本就不須要從父進程的地址空間中拷貝內容,這樣就節省了內存同時又提升了速度。

這個邏輯能夠敘述爲:對一個通常變量a(isref=0)進行通常的賦值操做,若是a所指向的zval的計數refcount大於1,那麼須要爲a從新分配一個新的zval,而且把以前的zval的計數refcount減小1。數組

PHP5.3版本中對於新的GC算法(Concurrent Cycle Collection in Reference Counted Systems)

幾個基本準則:函數

  1. 若是一個zval的refcount增長,那麼此zval還在使用,不屬於垃圾
  2. 若是一個zval的refcount減小到0,那麼zval能夠被釋放掉,不屬於垃圾
  3. 若是一個zval的refcount減小以後大於0,那麼此zval還不能被釋放,此zval可能成爲一個垃圾。

新的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自己實現了垃圾回收處理機制。

PHP5.2中的垃圾回收算法---Reference Counting

這個算法叫作「引用計數」,其思想很是直觀和簡潔:爲每一個內存對象分配一個計數器,當一個內存對象創建時計數器初始化爲1(所以此時老是有一個變量引用此對象),之後每有一個新變量引用此內存對象,則計數器加1,而每當減小一個引用此內存對象的變量則計數器減1,當垃圾回收機制運做時,將全部計數器爲0的內存對象銷燬並回收其佔用的內存。而php中內存對象就是zval,而計數器就是refcount__gc。
相關文章
相關標籤/搜索