いつか作ります RSSフィード

2009-06-24

[]PHPではガンガン変数を複製してかまわない 21:22 PHPではガンガン変数を複製してかまわない - いつか作ります を含むブックマーク はてなブックマーク - PHPではガンガン変数を複製してかまわない - いつか作ります PHPではガンガン変数を複製してかまわない - いつか作ります のブックマークコメント

期待したのに!

Don't copy variables for no reason. Sometimes PHP novices attempt to make their code "cleaner" by copying predefined variables to variables with shorter names. What this actually results in is doubled memory consumption, and therefore, slow scripts. In the following example, imagine if a malicious user had inserted 512KB worth of characters into a textarea field. This would result in 1MB of memory being used!

BAD: $description = $_POST['description']; echo $description;

GOOD: echo $_POST['description'];

大嘘をこくなクソッタレ。

検証

面倒なので、メモリ使用量は上限で測る。つまり、落ちるか落ちないかだけ見る。

//前提1:これは落ちない

$str1 = str_repeat('1', 30000000);

//前提2:これは落ちる(メモリ不足)

$str1 = str_repeat('1', 30000000);

$str2 = str_repeat('1', 30000000);

という状態になるまで適当に数字をいじる。ここから開始。で、

変数を複製してみる

//これは落ちない

$str1 = str_repeat('1', 30000000);

$str2 = $str1;

googleの主張に拠ればこのコードを実行したら前提2のコードと同じだけメモリを食う、つまり前提1の倍メモリを食うので、落ちなければいけない。のだが、実際は落ちない。ここ、驚くところね。

つまり、PHPでは、変数を別の変数に代入しても、メモリ上では変数は複製されない。

ちなみにこうすると落ちる。

//これは落ちる

$str1 = str_repeat('1', 30000000);

$str2 = $str1;

$str2 = $str2 . '1';

ポインターを示すのが面倒なので結論だけ言うと、PHPは値を複製しても、本当に必要になるまでは値を複製せず、同じメモリ位置を参照し続ける。オリジナルとは別でメモリを確保する事が必要になった時に改めて別の場所にメモリを確保し、値を複製する。

最後の例だと、$str2が更新される時点(3行目)で初めて値が複製される。2行目の時点では30000000文字の文字列はメモリ上に1つしか存在しない。変数を複製しても、2倍のメモリが消費される、という事はない。

ちなみに、関数の引数でも同じ事が起きる。見た目には値渡しと同じように動作するのだが、実際は参照が渡されている。だから、引数に再代入するとかいう野蛮な行為にさえ及ばなければ、関数にはガンガン値渡しをして問題ない。メモリ管理などという低俗な事はC層が勝手にやってくれる。

(厳密にはポインタっぽいものの分や、こういう小賢しい管理をするためにメモリを食うので、変数のコピーがゼロコストというわけではない。が、そんな性能差を気にするようなシチュエーションならそもそもPHPなんぞ使うべきではない)

つうかechoとprintの性能差がどうのとか言ってるし。何ナノ秒の差だよそれ。これだからPHPerはダメだといわれるんだ。

ここにまた新たなPHP伝説が誕生した。

たとえGoogle社員でもPHPerは駄目

追記:

流石にツッコミが入ったらしく、修正が入っている。現在のサンプルならばメモリ消費量が増えるので、指摘自体は正しくなっている。

新着エントリは上に追加。コメントは「はてなユーザのみ」、公開設定はパブリック (だれでも閲覧ができます)。