suin.io

PHPのunset()とメモリの開放を調べてみた

suin2011年3月19日

メモリの使用量を調べるに当たって、検査用関数を作ってみた。初期メモリ使用量は無視して、純粋に変数で使われた容量を検出するもの。$initialMemoryUseですでに20バイトくらい使っている、というのは誤差の範囲で^^

function dumpMemory()
{
    static $initialMemoryUse = null;

    if ( $initialMemoryUse === null )
    {
        $initialMemoryUse = memory_get_usage();
    }

    var_dump(number_format(memory_get_usage() - $initialMemoryUse));
}

ケース1

dumpMemory(); // string(1) "0"

$hoge = array();

dumpMemory(); // string(3) "184"

for ( $i = 1; $i < 10000; $i++ )
{
    $hoge[$i] = null;
}

dumpMemory(); // string(7) "785,720"

for ( $i = 1; $i < 10000; $i++ )
{
    unset($hoge[$i]);
}

dumpMemory(); // string(6) "65,764"

んー、なんかものすごいオーバヘッドがあるんだけど。

ケース2

dumpMemory(); // string(1) "0"

$hoge = array();

dumpMemory(); // string(3) "184"

for ( $i = 1; $i < 10000; $i++ )
{
    $hoge[$i] = null;
    unset($hoge[$i]);
}

dumpMemory(); // string(3) "260"

ケース1の変形版。unsetのタイミングをforの中にしてみたら、かなりオーバヘッドが減った。理由はわかんない。

ケース3

dumpMemory(); // string(1) "0"

$hoge = array();

dumpMemory(); // string(3) "184"

for ( $i = 1; $i < 10000; $i++ )
{
    $hoge[$i] = null;
}

dumpMemory(); // string(7) "785,732"

unset($hoge);

dumpMemory(); // string(2) "96"

これもまたケース1の変形版。forunset()しないで、配列まるごとunset()するようにしてみた。ケース2よりもオーバヘッドはひどくない。

ケース4

function scopeTest()
{
    $array = range(1, 10000);
    dumpMemory();
    // ここで$arrayはスコープを失う
}

dumpMemory(); // string(1) "0"

scopeTest(); // string(7) "785,700"

dumpMemory(); // string(2) "20"

今度はスコープでの実験。スコープが切れた変数はメモリから解放されると聞いていたけど、実際そのとおりみたい。

ケース5

class TestClass
{
    public static function test()
    {
        $array = range(1, 10000);
        dumpMemory();
        // ここでスコープを失う
    }
}

dumpMemory(); // string(1) "0"

TestClass::test(); // string(7) "785,680"

dumpMemory(); // string(2) "20"

ケース4をクラスにしてみただけ。静的関数でもスコープが切れた段階で、メモリが開放されていた。

結論みたいなもの

  • スコープ(寿命)が短い変数は特にunset()する必要はない。
  • グローバル(=寿命が長い)は変数は、うまいタイミングでunset()するか、できるだけスコープを短くしたほうがいい。
  • unset()の仕方によってはオーバヘッドがひどい。

ApacheからPHPを実行するくらいなら、プロセス自体の寿命も短いからメモリなんてそうそう気にならないけど、PHPでバッチ処理をしようとするとメモリ管理も大変になるんだよなあ。扱うデータ量が全然違ってくるし、プロセスの寿命も長いし。メモリを気にするならPHPなんてやめちまえ、ってこと?

RELATED POSTS