首頁  >  文章  >  後端開發  >  PHP中的GC機制詳解

PHP中的GC機制詳解

*文
*文原創
2017-12-27 14:12:384258瀏覽

本文主要介紹了解讀PHP中的垃圾回收機制,是否擁有GC功能是一門程式語言開發的重要重點。希望對大家有幫助。

PHP的基本GC概念
PHP語言同其他語言一樣,具有垃圾回收機制。那麼今天我們要為大家講解的內容就是關於PHP垃圾回收機制的相關問題。希望對大家有幫助。 PHP strtotime應用經驗之談PHP memory_get_usage()管理記憶體PHP unset全域變數運用問題詳談PHP unset()函數銷毀變數教你快速實作PHP全站權限驗證一、PHP 垃圾回收機制(Garbage Collector 簡稱GC) 在PHP中,沒有任何變數指向這個物件時,這個物件就變成垃圾。 PHP會將其在記憶體中銷毀;這是PHP的GC垃圾處理機制,防止記憶體溢出。當一個PHP執行緒結束時,目前佔用的所有記憶體空間都會被銷毀,目前程式中所有物件同時被銷毀。 GC程序一般都跟著每起一個SESSION而開始運行的.gc目的是為了在session文件過期以後自動銷毀刪除這些文件.二、__destruct /unset __destruct() 析構函數,是在垃圾對像被回收時執行。
unset 銷毀的是指向物件的變量,而不是這個物件。三、 Session 與PHP垃圾回收機制由於PHP的工作機制,它並沒有一個daemon線程來定期的掃描Session信息並判斷其是否失效,當一個有效的請求發生時,PHP 會根據全局變量session.gc_probability和session .gc_pisor的值,來決定是否啟用一個GC, 在預設情況下,session.gc_probability=1, session.gc_pisor =100也就是說有1%的可能性啟動GC(也就是說100個請求中只有一個gc會伴隨100個中的某個請求而啟動).PHP垃圾回收機制的工作就是掃描所有的Session信息,用當前時間減去session最後修改的時間,同session.gc_maxlifetime參數進行比較,如果生存時間超過gc_maxlifetime (預設24分鐘),就將該session刪除。
但是,如果你Web伺服器有多個站點,多個站點時,GC處理session可能會出現意想不到的結果,原因就是:GC在工作時,並不會區分不同站點的session.那麼這個時候怎麼解決呢?
1. 修改session.save_path,或使用session_save_path()讓每個站點的session保存到一個專用目錄,
2. 提供GC的啟動率,自然,PHP垃圾回收機制的啟動率提高,系統的性能也會隨之減低,不建議。
3. 在程式碼中判斷目前session的生存時間,利用session_destroy()刪除。


引用計數基本知識
每個php變數存在一個叫做"zval"的變數容器中.一個zval變數容器,除了包含變數的型別和值,還包括兩個位元組的額外資訊。第一個是"is_ref",是個bool值,用來標識這個變數是否是屬於引用集合(reference set).透過這個位元組,php引擎才能把普通變數和引用變數區分開.由於php允許使用者透過使用&來使用自訂引用,zval變數容器中還有一個內部引用計數機制,來優化記憶體使用.第二個額外位元組是"refcount",用來表示指向這個zval變數容器的變數(也稱符號即symbol)個數.

當一個變數被賦常量值時,就會產生一個zval變數容器,如下例所示:


  <?php 
      $a = "new string"; 
  ?>



在上例中,新的變數是a,是在目前作用域中產生的.並且產生了類型為string和值為"new string"的變數容器.在額外的兩個位元組資訊中,"is_ref"被預設為false,因為沒有任何自訂的引用生成."refcount"被設定為1,因為這裡只有一個變數使用這個變數容器.呼叫xdebug查看變數內容:


  <?php 
      $a = "new string";
      xdebug_debug_zval(&#39;a&#39;); 
  ?>



以上程式碼會輸出:


  a: (refcount=1, is_ref=0)=&#39;new string&#39;



對變數a增加一個引用計數


  <?php 
      $a = "new string"; 
      $b = $a; 
      xdebug_debug_zval(&#39;a&#39;); 
  ?>



以上程式碼會輸出:


  a: (refcount=2, is_ref=0)=&#39;new string&#39;



#這時,引用次數是2,因為同一變數容器被變數a和變數b關聯.當沒必要時,php不會去複製已產生的變數容器.變數容器在"refcount"變成0時就被銷毀.當任何關聯到某個變數容易的變數離開它的作用域(例如:函數執行結束),或是對變數呼叫了unset()函數,"refcount"就會減1,下面例子就能說明:


<?php 
  $a = "new string"; 
  $b = $c = $a; 
  xdebug_debug_zval(&#39;a&#39;); 
  unset($b, $c); 
  xdebug_debug_zval(&#39;a&#39;); 
?>



以上程式碼會輸出:


#
  a: (refcount=3, is_ref=0)=&#39;new string&#39; a: (refcount=1, is_ref=0)=&#39;new string&#39;

如果我們現在執行unset($a),$包含的這個類型和值的容器就會從記憶體刪除

複合型別(compound types)

當考慮像array和object這樣的複合型別(compound types)


當考慮像array和object這樣的複合型別(compound types)

######當考慮像array和object這樣的複合型別時,事情會稍微有些複雜.與標量(scalar)類型的值不同,array和object類型的變數把它們的成員或屬性存在自己的符號表中.這意味著下面的例子將產生三個zval變數容器##### #######
<?php 
  $a = array(&#39;meaning&#39; => &#39;life&#39;, &#39;number&#39; => 42);
  xdebug_debug_zval(&#39;a&#39;); 
?>

以上代码输出:


  a: (refcount=1, is_ref=0)=array (&#39;meaning&#39; => (refcount=1, is_ref=0)=&#39;life&#39;, &#39;number&#39; => (refcount=1, is_ref=0)=42)

这三个zval变量容器是:a,meaning,number.增加和减少refcount的规则和上面提到的一样


特例,添加数组本身作为数组元素时:


<?php 
  $a = array(&#39;one&#39;); 
  $a[] = &$a; 
  xdebug_debug_zval(&#39;a&#39;); 
?>

以上代码输出的结果:


  a: (refcount=2, is_ref=1)=array (0 => (refcount=1, is_ref=0)=&#39;one&#39;, 1 => (refcount=2, is_ref=1)=...)

可以看到数组a和数组本身元素a[1]指向的变量容器refcount为2

当对数组$a调用unset函数时,$a的refcount变为1,发生了内存泄漏

清理变量容器的问题
尽管不再有某个作用域中的任何符号指向这个结构(就是变量容器),由于数组元素"1"仍然指向数组本身,所以这个容器不能被消除.因为没有另外的符号指向它,用户没有办法清除这个结构,结果就会导致内存泄漏.庆幸的是,php将在请求结束时清除这个数据结构,但是php清除前,将耗费不少内存空间


回收周期
5.3.0PHP使用了新的同步周期回收算法,来处理上面所说的内存泄漏问题

首先,我们先要建立一些基本规则:
如果一个引用计数增加,它将继续被使用,当然就不再垃圾中.如果引用技术减少到零,所在的变量容器将被清除(free).就是说,仅仅在引用计数减少到非零值时,才会产生垃圾周期(grabage cycle).其次,在一个垃圾周期中,通过检查引用计数是否减1,并且检查哪些变量容器的引用次数是零,来发现哪部分是垃圾

2015810114143348.png (429×552)

为避免不得不检查所有引用计数可能减少的垃圾周期,这个算法把所有可能根(possible roots 都是zval变量容器),放在根缓冲区(root buffer)中(用紫色标记),这样可以同时确保每个可能的垃圾根(possible garbage root)在缓冲区只出现一次.仅仅在根缓冲区满了时,才对缓冲区内部所有不同的变量容器执行垃圾回收操作。

相关推荐:

php底层分析的视频和课件分享

浅析PHP底层的运行机制和工作原理

PHP底层工作原理_PHP教程


以上是PHP中的GC機制詳解的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn