PHP回收機制性能方面考慮的因素

這裏主要有兩個領域對性能有影響。第一個是內存佔用空間的節省,另外一個是垃圾回收機制執行內存清理時的執行時間增長(run-time delay)。咱們將研究這兩個領域。 php

內存佔用空間的節省

首先,實現垃圾回收機制的整個緣由是爲了,一旦先決條件知足,經過清理循環引用的變量來節省內存佔用。在PHP執行中,一旦根緩衝區滿了或者調用gc_collect_cycles() 函數時,就會執行垃圾回收。在下圖中,顯示了下面腳本分別在PHP 5.2 和 PHP 5.3環境下的內存佔用狀況,其中排除了腳本啓動時PHP自己佔用的基本內存。 算法


Example #1 Memory usage example shell

<?php
class Foo
{
    public 
$var '3.1415962654';
}

$baseMemory memory_get_usage();

for ( 
$i 0$i <= 100000$i++ )
{
    
$a = new Foo;
    
$a->self $a;
    if ( 
$i 500 === )
    {
        echo 
sprintf'%8d: '$i ), memory_get_usage() - $baseMemory"\n";
    }
}
?>
Comparison of memory usage between PHP 5.2 and PHP 5.3


在這個很理論性的例子中,咱們建立了一個對象,這個對象中的一個屬性被設置爲指回對象自己。在循環的下一個重複(iteration)中,當腳本中的變量被從新複製時,就會發生典型性的內存泄漏。在這個例子中,兩個變量容器是泄漏的(對象容器和屬性容器),可是僅僅能找到一個可能根:就是被unset的那個變量。在10,000次重複後(也就產生總共10,000個可能根),當根緩衝區滿時,就執行垃圾回收機制,而且釋放那些關聯的可能根的內存。這從PHP 5.3的鋸齒型內存佔用圖中很容易就能看到。每次執行完10,000次重複後,執行垃圾回收,並釋放相關的重複使用的引用變量。在這個例子中因爲泄漏的數據結構很是簡單,因此垃圾回收機制自己沒必要作太多工做。從這個圖表中,你能看到 PHP 5.3的最大內存佔用大概是9 Mb,而PHP 5.2的內存佔用一直增長。 服務器

執行時間增長(Run-Time Slowdowns)

垃圾回收影響性能的第二個領域是它釋放已泄漏的內存耗費的時間。爲了看到這個耗時時多少,咱們稍微改變了上面的腳本,有更屢次數的重複而且刪除了循環中的內存佔用計算,第二個腳本代碼以下: 數據結構


Example #2 GC performance influences 函數

<?php
class Foo
{
    public 
$var '3.1415962654';
}

for ( 
$i 0$i <= 1000000$i++ )
{
    
$a = new Foo;
    
$a->self $a;
}

echo 
memory_get_peak_usage(), "\n";
?>


咱們將運行這個腳本兩次,一次經過配置zend.enable_gc 打開垃圾回收機制時,另外一次是它關閉時。 性能


Example #3 Running the above script 測試

time php -dzend.enable_gc=0 -dmemory_limit=-1 -n example2.php
# and
time php -dzend.enable_gc=1 -dmemory_limit=-1 -n example2.php


在個人機器上,第一個命令持續執行時間大概爲10.7秒,而第二個命令耗費11.4秒。時間上增長了7%。然而,執行這個腳本時內存佔用的峯值下降了98%,從931Mb 降到 10Mb。這個基準不是很科學,或者並不能表明真實應用程序的數據,可是它的確顯示了垃圾回收機制在內存佔用方面的好處。好消息就是,對這個腳本而言,在執行中出現更多的循環引用變量時,內存節省的更多的狀況下,每次時間增長的百分比都是7%。 spa

PHP內部 GC 統計信息

在PHP內部,能夠顯示更多的關於垃圾回收機制如何運行的信息。可是要顯示這些信息,你須要先從新編譯PHP使benchmark和data-collecting code可用。你須要在按照你的意願運行./configure前,把環境變量CFLAGS設置成-DGC_BENCH=1。下面的命令串就是作這個事: .net


Example #4 Recompiling PHP to enable GC benchmarking

export CFLAGS=-DGC_BENCH=1
./config.nice
make clean
make


當你用新編譯的PHP二進制文件來從新執行上面的例子代碼,在PHP執行結束後,你將看到下面的信息:


Example #5 GC statistics

GC Statistics
-------------
Runs:               110
Collected:          2072204
Root buffer length: 0
Root buffer peak:   10000

      Possible            Remove from  Marked
        Root    Buffered     buffer     grey
      --------  --------  -----------  ------
ZVAL   7175487   1491291    1241690   3611871
ZOBJ  28506264   1527980     677581   1025731


主要的信息統計在第一個塊。你能看到垃圾回收機制運行了110次,並且在這110次運行中,總共有超過兩百萬的內存分配被釋放。只要垃圾回收機制運行了至少一次,根緩衝區峯值(Root buffer peak)老是10000.

結論

一般,PHP中的垃圾回收機制,僅僅在循環回收算法確實運行時會有時間消耗上的增長。可是在日常的(更小的)腳本中應根本就沒有性能影響。

然而,在日常腳本中有循環回收機制運行的狀況下,內存的節省將容許更多這種腳本同時運行在你的服務器上。由於總共使用的內存沒達到上限。

這種好處在長時間運行腳本中尤爲明顯,諸如長時間的測試套件或者daemon腳本此類。同時,對一般比Web腳本運行時間長的» PHP-GTK應用程序,新的垃圾回收機制,應該會大大改變一直以來認爲內存泄漏問題難以解決的見解。

相關文章
相關標籤/搜索