理論的には、この記事はLinux for Everyoneブログで公開されることになっています。 ただし、この問題はpythonおよびperlの同様のテストでは現れなかったため、特にPHPとプラットフォームのビット深度に依存しています。 また、PHPは主にサイトに関連付けられているため、対応するブログがホストされています。
注意 ! 次のテキストには、ソースコードの断片
からの暴力的なシーンが含まれており、あなたの脳に回復不可能なダメージを与え、
人類の Linux PHPへの信頼を破壊する可能性があります。
すべては、64ビットアーキテクチャでは、次のPHPスクリプトが致命的に遅いという不満から始まりました。
<?php
$cnt=0;
while ($cnt++<5) {
echo '----- TEST #'.$cnt.'-----<br>';
echo 'start FOR & WHILE testing<br>';
$start = microtime(1);
for($i=0;$i<3000000;$i++) {}
$end = microtime(1);
$time = $end - $start;
echo $time.' for($i=0;$i<3000000;$i++) {}<br>';
$start = microtime(1);
$i=0; while($i++<3000001) {}
$end = microtime(1);
$time = $end - $start;
echo $time.' while($i++<3000001) {}<br>';
$start = microtime(1);
$i=0; while($i<3000000) {$i++;}
$end = microtime(1);
$time = $end - $start;
echo $time.' while($i<3000000) {$i++;}<br>';
$start = microtime(1);
$i = 0;
while ($i<3000000): $i++; endwhile;
$end = microtime(1);
$time = $end - $start;
echo $time.' while ($i<3000000): $i++; endwhile;<br>';
echo '<br><br>start a.=b & a=ab testing<br>';
$a = NULL;
$b = ' , 40';
$start = microtime(1);
for($i=0;$i<3000000;$i++) {$a = $a.$b;}
$end = microtime(1);
$time = $end - $start;
echo $time.' for($i=0;$i<3000000;$i++) {$a = $a.$b;}<br>';
$a = NULL;
$b = ' , 40';
$start = microtime(1);
for($i=0;$i<3000000;$i++) $a = $a.$b;
$end = microtime(1);
$time = $end - $start;
echo $time.' for($i=0;$i<3000000;$i++) $a = $a.$b;<br>';
$a = NULL;
$b = ' , 40';
$start = microtime(1);
for($i=0;$i<3000000;$i++) {$a .= $b;}
$end = microtime(1);
$time = $end - $start;
echo $time.' for($i=0;$i<3000000;$i++) {$a.=$b;}<br>';
$a = NULL;
$b = ' , 40';
$start = microtime(1);
for($i=0;$i<3000000;$i++) $a .= $b;
$end = microtime(1);
$time = $end - $start;
echo $time.' for($i=0;$i<3000000;$i++) $a .= $b;<br>';
$a = NULL;
$b = ' , 40';
$start = microtime(1);
$i=0; while($i++<3000001) {$a.= $b;}
$end = microtime(1);
$time = $end - $start;
echo $time.' while($i++<3000001) {$a.= $b;}<br>';
$a = NULL;
$b = ' , 40';
$start = microtime(1);
$i=0; while($i++<3000001) $a.= $b;
$end = microtime(1);
$time = $end - $start;
echo $time.' $i=0; while($i++<3000001) $a.= $b;<br>';
}
?>
実際、このような問題はphp5.2に存在し、さまざまなディストリビューションでテストされています。 その結果、問題は実際にビット深度に関連していました。 しかし、他のインタープリターで同様のコードのアナログをテストしたところ、判明しました-そこに同様の問題はありません。
したがって、それはもっぱらPHP自体の問題であり、64ビットで明らかになりました。 しかし、なぜそんなにたくさんの悪魔がいるのでしょうか?
i386、PAE、およびx86_64では異なる値を生成するstraceで起動されました。
- i386 mmap
- PAE mremap(論理的です。これはフラグ付きのmmapです)
- x86_64 brkおよびmmap(しかし、なぜbrk?)
このbrkとは何ですか、なぜphpの速度にそれほど影響するのですか?
まず、トピックの画像をクリックすると、メモリの操作に関するすべての詳細を開示する基本的な記事につながることに注意してください。 ただし、非常に複雑で英語です。 簡単に言うと、brkを使用すると、mmapを介して断片を食いつぶすのではなく、割り当てられたメモリのサイズを変更できるため、断片化が減少します。
しかし、ご覧のとおり、この操作は非常に高価であり、使用するメモリを減らすと、オーバーヘッドが非常に大きくなり、無視する方が適切です。 特に高負荷になると、メモリを節約するよりも応答速度がはるかに重要になります。
では、なぜi386ではmmapのみを使用し、x86_64ではbrkがそこに侵入するのでしょうか? この質問に答えるために、元のソースである
mallocを使用します。
Normally, malloc() allocates memory from the heap, and adjusts the size of the
heap as required, using sbrk(2). When allocating blocks of memory larger than
MMAP_THRESHOLD bytes, the glibc malloc() implementation allocates the memory
as a private anonymous mapping using mmap(2). MMAP_THRESHOLD is 128 kB by
default, but is adjustable using mallopt(3).
x86_64の場合、MMAP_THRESHOLDが増加し、このような興味深い結果につながりました。この結果は、PHPの非常にcなガベージコレクターと関連していたようです。
また、i386のようにmallocの呼び出しを返すには、古い値を返す必要があります。 これは、glibcをアセンブルすることでグローバルに変更できます。これは、望ましくないか、カーネル変数に古い値を指定することによりプロセスに対して選択的に行われます(glibcがこのオプションをサポートしてビルドされていない場合):
エクスポートMALLOC_MMAP_THRESHOLD_ = 131072
この魔法の行をapache initスクリプトに挿入すると、速度が向上し、メモリ消費が増加します。 もちろん、これはphpだけでなく、開発者がmallocを暗示するmmapを呼び出す開発者の他の多くのプログラムにも当てはまります。
PSテストはコンソールから実行するのが最適です。
strace php -f qq.phpは1つの画像を提供します
MALLOC_MMAP_THRESHOLD_ = 131072 strace php -f qq.phpは、64ビットを使用している場合、もちろん完全に異なるものを提供します。