PHP 性能的微觀分析

一、性能分析相關(guān)的函數(shù)與命令

1.1、時(shí)間度量函數(shù)

平時(shí)我們常用 time() 函數(shù),但是返回的是秒數(shù),對(duì)于某段代碼的內(nèi)部性能分析,到秒的精度是不夠的。于是要用 microtime 函數(shù)。而 microtime 函數(shù)可以返回兩種形式,一是字符串的形式,一是浮點(diǎn)數(shù)的形式。不過需要注意的是,在缺省的情況下,返回的精度只有4位小數(shù)。為了獲得更高的精確度,我們需要配置 precision。

如下是 microtime 的使用結(jié)果。

    $start= microtime(true);
    echo $start."\n";
    $end = microtime(true);
    echo $end."\n";
    echo ($end-$start)."\n";

輸出為:

    bash-3.2# phptime.php 

    1441360050.3286

    1441360050.3292

    0.00053000450134277

而在代碼前面加上一行:

     ini_set("precision", 16);

輸出為:

    bash-3.2# phptime.php

    1441360210.932628

    1441360210.932831

    0.0002031326293945312

除了 microtime 內(nèi)部統(tǒng)計(jì)之外, 還可以使用 getrusage 來(lái)取得用戶態(tài)的事長(zhǎng)。在實(shí)際的操作中,也常用 time 命令來(lái)計(jì)算整個(gè)程序的運(yùn)行時(shí)長(zhǎng),通過多次運(yùn)行或者修改代碼后運(yùn)行,得到不同的時(shí)間長(zhǎng)度以得到效率上的區(qū)別。 具體用法是:time phptime.php ,則在程序運(yùn)行完成之后,不管是否正常結(jié)束退出,都會(huì)有相關(guān)的統(tǒng)計(jì)。

    bash-3.2# time phptime.php

    1441360373.150756

    1441360373.150959

    0.0002031326293945312

    real    0m0.186s

    user    0m0.072s

    sys     0m0.077s

因?yàn)楸疚乃懻摰男阅軉栴},往往分析上百萬(wàn)次調(diào)用之后的差距與趨勢(shì),為了避免代碼中存在一些時(shí)間統(tǒng)計(jì)代碼,后面我們使用 time 命令居多。

1.2、內(nèi)存使用相關(guān)函數(shù)

分析內(nèi)存使用的函數(shù)有兩個(gè):memory_ get_ usage、memory_ get_ peak_usage,前者可以獲得程序在調(diào)用的時(shí)間點(diǎn),即當(dāng)前所使用的內(nèi)存,后者可以獲得到目前為止高峰時(shí)期所使用的內(nèi)存。所使用的內(nèi)存以字節(jié)為單位。

    $base_memory= memory_get_usage();
    echo "Hello,world!\n";
    $end_memory= memory_get_usage();
    $peak_memory= memory_get_peak_usage();
    echo $base_memory,"\t",$end_memory,"\t",($end_memory-$base_memory),"\t", $peak_memory,"\n";

輸出如下:

    bash-3.2# phphelloworld.php

    Hello,world!

    224400  224568  168     227424

可以看到,即使程序中間只輸出了一句話,再加上變量存儲(chǔ),也消耗了168個(gè)字節(jié)的內(nèi)存。

對(duì)于同一程序,不同 PHP 版本對(duì)內(nèi)存的使用并不相同,甚至還差別很大。 

   $baseMemory= memory_get_usage();
    class User
    {
    private $uid;
    function __construct($uid)
        {
    $this->uid= $uid;
        }
    }
    
    for($i=0;$i<100000;$i++)
    {
    $obj= new User($i);
    if ( $i% 10000 === 0 )
        {
    echo sprintf( '%6d: ', $i), memory_get_usage(), " bytes\n";
        }
    }
    echo "  peak: ",memory_get_peak_usage(true), " bytes\n"; 

在 PHP 5.2 中,內(nèi)存使用如下:

    [root@localhostphpperf]# php52 memory.php

    0: 93784 bytes
    10000: 93784 bytes
    ……
    80000: 93784 bytes
    90000: 93784 bytes
    peak: 262144 bytes

PHP 5.3 中,內(nèi)存使用如下

    [root@localhostphpperf]# phpmemory.php

    0: 634992 bytes
    10000: 634992 bytes
    ……
    80000: 634992 bytes
    90000: 634992 bytes
    peak: 786432 bytes

可見 PHP 5.3 在內(nèi)存使用上要粗放了一些。 

PHP 5.4 - 5.6 差不多,有所優(yōu)化:   

 [root@localhostphpperf]# php56 memory.php

    0: 224944 bytes
    10000: 224920 bytes
    ……
    80000: 224920 bytes
    90000: 224920 bytes
    peak: 262144 bytes

而 PHP 7 在少量使用時(shí),高峰內(nèi)存的使用,增大很多。

  [root@localhostphpperf]# php7 memory.php

    0: 353912 bytes
    10000: 353912 bytes
    ……
    80000: 353912 bytes
    90000: 353912 bytes
    peak: 2097152 bytes

從上面也看到,以上所使用的 PHP 都有比較好的垃圾回收機(jī)制,10萬(wàn)次初始化,并沒有隨著對(duì)象初始化的增多而增加內(nèi)存的使用。PHP7 的高峰內(nèi)存使用最多,達(dá)到了接近 2M。

下面再來(lái)看一個(gè)例子,在上面的代碼的基礎(chǔ)上,我們加上一行,即如下加粗的一行:

    $obj->self = $obj;

代碼如下:

    $baseMemory= memory_get_usage();
    class User
    {
    private $uid;
    function __construct($uid)
        {
    $this->uid= $uid;
        }
    }
    
    for($i=0;$i<100000;$i++)
    {
    $obj= new User($i);
    $obj->self = $obj;
    if ( $i% 5000 === 0 )
        {
    echo sprintf( '%6d: ', $i), memory_get_usage(), " bytes\n";
        }
    }

 

    echo "  peak: ",memory_get_peak_usage(true), " bytes\n";

  哈爾濱品用軟件有限公司致力于為哈爾濱的中小企業(yè)制作大氣、美觀的優(yōu)秀網(wǎng)站,并且能夠搭建符合百度排名規(guī)范的網(wǎng)站基底,使您的網(wǎng)站無(wú)需額外費(fèi)用,即可穩(wěn)步提升排名至首頁(yè)。歡迎體驗(yàn)最佳的哈爾濱網(wǎng)站建設(shè)。