首先咱先看到例子,最簡單不過的執行流程了:
Example 1: gc.php
<?php
error_reporting(E_ALL);
$a = 'I am test.';
$b = & $a;
echo $b ."\n";
?>
不用說 % php -f gc.php 輸出結果很是明瞭:
hy0kl% php -f gc.php
I am test.
好,下一個:
Example 2:
<?php
error_reporting(E_ALL);
$a = 'I am test.';
$b = & $a;
$b = 'I will change?';
echo $a ."\n";
echo $b ."\n";
?>
執行結果依然很明顯:
hy0kl% php -f gc.php
I will change?
I will change?
君請看:
Example 3:
<?php
error_reporting(E_ALL);
$a = 'I am test.';
$b = & $a;
unset($a);
echo $a ."\n";
echo $b ."\n";
?>
是否是得想一下下呢?
hy0kl% php -f gc.php
Notice: Undefined variable: a in /usr/local/www/apache22/data/test/gc.php on line 8
I am test.
有點犯迷糊了嗎?
君再看:
Example 4:
<?php
error_reporting(E_ALL);
$a = 'I am test.';
$b = & $a;
unset($b);
echo $a ."\n";
echo $b ."\n";
?>
其實若是 Example 3 理解了,這個與之殊途同歸.
hy0kl% php -f gc.php
I am test.
Notice: Undefined variable: b in /usr/local/www/apache22/data/test/gc.php on line 9
君且看:
Example 5:
<?php
error_reporting(E_ALL);
$a = 'I am test.';
$b = & $a;
$a = null;
echo '$a = '. $a ."\n";
echo '$b = '. $b ."\n";
?>
猛的第一感受是什麼樣的?
hy0kl% php -f gc.php
$a =
$b =
沒錯,這就是輸出結果,對 PHP GC 已有深刻理解的 phper 不會以爲有什麼奇怪,說實話,當我第一次運行這段代碼時很意外,卻讓我對 PHP GC 有更深入的理解了.那麼下面與之同工的例子天然好理解了.
Example 6:
<?php
error_reporting(E_ALL);
$a = 'I am test.';
$b = & $a;
$b = null;
echo '$a = '. $a ."\n";
echo '$b = '. $b ."\n";
?>
OK,若是上面的例子的結果對看官來講無任何細節可言,那您可關閉本窗口了,歡迎有空再來!
下面咱們來詳細分析 GC 與引用.
1. 全部例子中,建立了一個變量,這個過程通俗一點講:是在內存中開闢了一塊空間,在裏面存放了一個字符串 I am test. . PHP 內部有個符號表,用來記錄各塊內存引用計數,那麼此時會將這塊內存的引用計數 加 1,而且用一個名爲 $a 的標籤(變量)指向這塊內存,方便依標籤名來操做內存.
2. 對變量 $a 進行 & 操做,個人理解是找到 $a 所指向的內存,併爲 $b 創建一樣的一引用指向,並將存放字符串 I am test. 的內存塊在符號表中引用計數 加 1.換言之,咱們的腳本執行到這一行的時候,存放字符串 I am test. 的那塊內存被引用了兩次.這裏要強調的是,& 操做是創建了引用指向,而不是指針, PHP 沒有指針的概念!同時有人提出說相似於 UNIX 的文件軟連接.能夠在必定程度上這麼理解: 存放字符 I am test. 的那塊內存是咱們的一個真實的文件,而變量 $a 與 $b 是針對真實文件創建的軟連接,但它們指向的是同一個真實文件. So, 咱們看到,在 Example 2 中給 $b 賦值的同時, $a 的值也跟着變化了.與經過某一軟鏈操做了文件相似.
3. 在 Example 3 與 4 中,進行了 unset() 操做.根據實際的執行結果,能夠看出: unset() 只是斷開這個變量對它原先指向的內存的引用,使變量自己成爲沒有定義過空引用,所在調用時發出了 Notice ,而且使那塊內存在符號表中引用計數 減 1,並無影響到其餘指向這塊內存的變量.換言之,只有當一塊內存在符號表中的引用計數爲 0 時, PHP 引擎纔會將這塊內存回收.
PHP 手冊
4.0.0 unset() became an expression. (In PHP 3, unset() would always return 1).
這意味着什麼?
看看下面的代碼與其結果:
<?php
error_reporting(E_ALL);
$a = 'I am test.';
$b = & $a;
unset($a);
unset($a);
unset($a);
echo '$a = '. $a ."\n";
echo '$b = '. $b ."\n";
?>
hy0kl% php -f gc.php
Notice: Undefined variable: a in /usr/local/www/apache22/data/test/gc.php on line 10
$a =
$b = I am test.
第一次 unset() 的操做已經斷開了指向,因此後繼的操做不會對符號表的任何內存的引用記數形成影響了.
4. 經過 Example 5 & 6 能夠明確無誤得出: 賦值 null操做是至關猛的,它會直接將變量所指向的內存在符號號中的引用計數置 0,那這塊內存天然被引擎回收了,至於什麼時候被再次利用不得而知,有可能立刻被用做存儲別的信息,也許再也沒有使用過.可是不管如何,原來全部指向那塊內存變量都將沒法再操做被回收的內存了,任何試圖調用它的變量都將返回 null.
<?php
error_reporting(E_ALL);
$a = 'I am test.';
$b = & $a;
$b = null;
echo '$a = '. $a ."\n";
echo '$b = '. $b ."\n";
if (null === $a)
{
echo '$a is null.';
} else
{
echo 'The type of $a is unknown.';
}
?>
hy0kl% php -f gc.php
$a =
$b =
$a is null.
綜上所述,充分說明了爲何咱們在看開源產品源碼的時候,常看到一些比較大的臨時變量,或使用完再也不調用的重用信息都會被集中或顯示的賦值爲 null 了.它至關於 UNIX 中直接將真實文件幹掉了,全部指向它的軟連接天然成了空鏈了.
以前在討論到這些細節點時有不少想固然的念頭,在實際的執行了測試代碼後才發現: 哦,原來如此!php