メモリの使用量を調べるに当たって、検査用関数を作ってみた。初期メモリ使用量は無視して、純粋に変数で使われた容量を検出するもの。$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の変形版。for
でunset()
しないで、配列まるごと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なんてやめちまえ、ってこと?