程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> 網頁編程 >> PHP編程 >> 關於PHP編程 >> PHP線程的內存回收問題,php線程回收

PHP線程的內存回收問題,php線程回收

編輯:關於PHP編程

PHP線程的內存回收問題,php線程回收


當一個PHP線程結束時,當前占用的所有內存空間都會被銷毀。那麼如果這個線程不結束,怎麼回收內存呢?

refcount:引用技術器,可以理解為指向該個容器的指針個數吧。

is_ref:是否被引用(只可能是0或者1)

賦值的流程:

<?php
$a = 'aa';
xdebug_debug_zval(a); //(refcount=1, is_ref=0),string 'aa' (length=6)
$b = $a; 
//以下的兩個其實是一個變量容器
xdebug_debug_zval(a); //(refcount=2, is_ref=0),string 'aa' (length=6)
xdebug_debug_zval(b); //(refcount=2, is_ref=0),string 'aa' (length=6)
unset($b); //對變量容器 refcount 減1
xdebug_debug_zval(a); //(refcount=1, is_ref=0),string 'aa' (length=6)
xdebug_debug_zval(b); //b: no such symbol b變量被銷毀,指向被斷掉,如果對應容器的引用技術為零,那麼該塊兒內存被回收
$b = $a;
$b = 'bb';
xdebug_debug_zval(a); //(refcount=1, is_ref=0),string 'aa' (length=6)
xdebug_debug_zval(b); //(refcount=1, is_ref=0),string 'aa' (length=6) 重新申請一個變量容器存儲b,a的變量容器引用減1

引用的流程:

<?php
$a = 'aa';
xdebug_debug_zval('a'); //(refcount=1, is_ref=0),string 'aa' (length=2)
$b = & $a;
//變量容器的引用技術加1,引用標記置為1
xdebug_debug_zval('a'); //(refcount=2, is_ref=1),string 'aa' (length=2)
xdebug_debug_zval('b'); //(refcount=2, is_ref=1),string 'aa' (length=2)
$b = '123'; 
//php會發現,該容器變量是引用(is_ref),所以容器變量不用像賦值那樣再申請一個
xdebug_debug_zval('a'); //(refcount=2, is_ref=1),string '123' (length=2)
xdebug_debug_zval('b'); //(refcount=2, is_ref=1),string '123' (length=2)
unset($b);
//變量容器應用計數減1,引用為零
xdebug_debug_zval('a'); //(refcount=1, is_ref=0),string '123' (length=2)
xdebug_debug_zval('b'); // b: no such symbol

那如果多次引用,unset掉一個,is_ref是否會被置為零,那樣bug不就出現了麼?變量容器還是引用啊。那麼我們來看看:

<?php
$a = 'aa';
$b = &$a;
$c = &$a;
//可以看到引用refCount是3,is_ref永遠是1
xdebug_debug_zval('a'); //(refcount=3, is_ref=1),string 'aa' (length=2)
xdebug_debug_zval('b'); //(refcount=3, is_ref=1),string 'aa' (length=2)
xdebug_debug_zval('c'); //(refcount=3, is_ref=1),string 'aa' (length=2)

unset($b);
//我們期待的bug沒有出現,只是refcount減1,is_ref還是1
xdebug_debug_zval('a'); //(refcount=2, is_ref=1),string 'aa' (length=2)
xdebug_debug_zval('b'); // b: no such symbol
xdebug_debug_zval('c'); //(refcount=2, is_ref=1),string 'aa' (length=2)
//那php它怎麼知道這個容器還有引用,畢竟is_ref仍然是1,不能計數,那麼現在refcount就起作用了,是它告訴php,該變量有幾個引用,但問題又來了,如果我干點壞事,在引用的時候,又賦值,它會不會有bug
$e = $a;
//我們看到期望的bug還是沒出現,這時候再賦值,就不像直接賦值那麼簡單refcount加1了,而是申請了一個新的變量容器
xdebug_debug_zval('a'); //(refcount=2, is_ref=1),string 'aa' (length=2)
xdebug_debug_zval('e'); //(refcount=1, is_ref=0),string 'aa' (length=2)

unset和賦值null都能回收變量麼?很多人都錯認為,這兩個都能回收變量空間,其實錯了,null只是把變量占用的空間變小了,從回收上來說,該容器依然存在。

<?php
$a = 'aa';
$b = $a;
$b = null;
//又申請了一個變量容器
xdebug_debug_zval('a'); //(refcount=1, is_ref=0),string 'aa' (length=2)
xdebug_debug_zval('b'); //(refcount=1, is_ref=0),null 變量空間並沒被回收
unset($b);
//這時候才釋放了b變量容器的空間
xdebug_debug_zval('a'); //(refcount=1, is_ref=0),string 'aa' (length=2)
xdebug_debug_zval('b'); //b: no such symbol

總結

1. 垃圾回收的時機

PHP中,引用計數為0,則內存立刻釋放。也就是說,不存在環狀引用的變量,離開變量的作用域,內存被立刻釋放。環狀引用檢測則是在滿足一定條件下觸發,所以在上面的例子中,會看到使用的內存有大幅度的波動。也可以通過 gc_collect_cycles 函數來主動進行環狀引用檢測。

2. &符號的影響

顯式引用一個變量,會增加該內存的引用計數:

$a = "something";
$b = &$a;
此時unset($a), 但是仍有$b指向該內存區域的引用,內存不會釋放。

3. unset函數的影響

unset只是斷開一個變量到一塊內存區域的連接,同時將該內存區域的引用計數-1;在上面的例子中,循環體內部,$a=new A(); unset($a);並不會將$a的引用計數減到零;

4. = null 操作的影響;

$a = null 是直接將$a 指向的數據結構置空,同時將其引用計數歸0。

5. 腳本執行結束的影響

腳本執行結束,該腳本中使用的所有內存都會被釋放,不論是否有引用環。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved