July 10, 2014

PHP5.5 で "continue 2" したらメモリ使用量が増えた

PHP5.5 で "continue 2" したらメモリ使用量が増えている気がしたので、簡単に検証してみました。

使ったソースは以下です。
<?php

/**
 * メモリ使用量をKB表記で返す
 *
 * @return string
 */
function peak_usage() {
    return (memory_get_peak_usage(true) / 1024).'KB'.PHP_EOL;
}

// 100要素数の配列を作る
// 各要素には ['a', 'b', 'c'] が入る
$array = [];
for($i = 0; $i < 100; $i++) {
    $array[] = ['a', 'b', 'c'];
}

// もう一つ適当に配列を作る
$array2 = ['x' => 'X', 'y' => 'Y'];

// $array * $array2 を反復を 100 回行う
// $array * $array2 の反復の中で即時 continue 2 する
for($i = 0; $i < 100; $i++) {
    if ($i % 10 === 0) {
        echo php_sapi_name() === 'cli' ? peak_usage() : nl2br(peak_usage());
    }

    foreach ($array as $key => $value) {
        foreach ($array2 as $key2 => $value2) {
            continue 2;
        }
    }
}
まずは、PHP 5.4 (OS X Mavericks) で確認してみます。
$ php -v
PHP 5.4.24 (cli) (built: Jan 19 2014 21:32:15)
Copyright (c) 1997-2013 The PHP Group
Zend Engine v2.4.0, Copyright (c) 1998-2013 Zend Technologies
ブラウザからアクセス (ビルトインサーバーで実行)
512KB
512KB
512KB
512KB
512KB
512KB
512KB
512KB
512KB
512KB
コマンドラインから実行
512KB
512KB
512KB
512KB
512KB
512KB
512KB
512KB
512KB
512KB
結果に違いはありませんでした。

次に、PHP 5.5 (Vagrant x Ubuntu 13.10) で確認してみます。
$ php -v
PHP 5.5.12-2+deb.sury.org~saucy+1 (cli) (built: May 12 2014 13:45:47)
Copyright (c) 1997-2014 The PHP Group
Zend Engine v2.5.0, Copyright (c) 1998-2014 Zend Technologies
    with Xdebug v2.2.3, Copyright (c) 2002-2013, by Derick Rethans
    with Zend OPcache v7.0.4-dev, Copyright (c) 1999-2014, by Zend Technologies

$ apache2 -v
Server version: Apache/2.4.9 (Ubuntu)
Server built:   Apr  1 2014 08:58:43
ブラウザからアクセスした結果 (Apacheで実行)
512KB
768KB
1280KB
1536KB
2048KB
2304KB
2816KB
3072KB
3584KB
3840KB
コマンドラインから実行した結果
512KB
512KB
512KB
512KB
512KB
512KB
512KB
512KB
512KB
512KB
ブラウザからアクセスした時に、かなり増えました。ちなみに "continue 2" の箇所をコメントアウトすると、ブラウザからアクセスした時も、ずっと "512KB" のままになりました。

Stack Overflowに以下の投稿が見つかり、"Zend OPcache"に関することが書かれています。
http://stackoverflow.com/questions/23231675/php-5-5-memory-leak-when-using-continue-2-inside-two-foreach-loops

2014-07-11 追記: PHP本家にも報告されていました。
https://bugs.php.net/bug.php?id=67111

再現条件は良くわかりませんが、Zend OPcacheのバグっぽいですね。

尚、foreach()している箇所をwhile()に変えたら、増加は発生せず、ずっと"512KB"となりました。応急処置するなら、この方法ですかねぇ。
reset($array);
while (list($key, $value) = each($array)) {
    reset($array2);
    while (list($key2, $value2) = each($array2)) {
        continue 2;
    }
}

No comments:

Post a Comment