web-dev-qa-db-ja.com

PHPでのメモリ使用量の追跡

URLを処理するスクリプトのメモリ使用量を追跡しようとしています。基本的な考え方は、別のURLをcURLマルチハンドラーに追加する前に、適切なバッファーがあることを確認することです。マルチハンドラーの実行中にURLデータを処理する「ローリングcURL」の概念を使用しています。つまり、既存のURLが処理されて削除されるたびにプールから新しいURLを追加することにより、N個の接続をアクティブに保つことができます。

memory_get_usage()を使用したところ、いくつかの肯定的な結果が得られました。 _real_usage_フラグを追加すると役立ちました(「システム」メモリと「emalloc」メモリの違いは明確ではありませんが、システムはより大きな数値を表示します)。 memory_get_usage()は、URLが追加されると増加し、URLセットが枯渇すると減少します。ただし、最後のメモリチェックが〜18Mで、32Mの制限を超えました。

CURL multiが要求が返されるたびにメモリ使用量をポーリングします。複数のリクエストが同時に返される可能性があるため、多数のURLが同時にデータを返し、14Mのメモリ使用量を実際にジャンプする可能性があります。ただし、memory_get_usage()が正確な場合、それが起こっていると思います。

[更新:質問する前にさらにテストを実行する必要があり、PHPのメモリ制限が増加しました(ただし、スクリプトで「安全な」量は同じままでした)。 25Mから32Mを超える制限を課しました。次に、予想どおり、URLが追加されていない場所でゆっくりと下降しました。しかし、質問は残しておきます。これは正しい方法ですか?]

この方法でmemory_get_usage()を信頼できますか?メモリ使用量を取得するためのより良い代替方法はありますか(シェルコマンドの出力を解析するスクリプトを見たことがありますか?)

32
Tim Lytle

_real_usage_は次のように機能します。

Zendのメモリマネージャは、必要なすべてのブロックにシステムmallocを使用しません。代わりに、システムメモリの大きなブロックを割り当て(256K単位で、環境変数_ZEND_MM_SEG_SIZE_を設定することで変更できます)、内部で管理します。したがって、2種類のメモリ使用量があります。

  1. エンジンがOSから使用したメモリ量(「実際の使用量」)
  2. このメモリのどれだけがアプリケーションによって実際に使用されたか(「内部使用」)

これらのいずれかがmemory_get_usage()によって返されます。どちらがあなたにとってより有用であるかは、あなたが探しているものに依存します。特定の部分でコードを最適化することを検討している場合は、「内部」がより役立つ場合があります。メモリ使用量をグローバルに追跡している場合、「実際の」がより有用です。 _memory_limit_は「実」数を制限するため、制限によって許可されているすべてのブロックがシステムから取得され、メモリマネージャーが要求されたブロックを割り当てることができないとすぐに、割り当てが失敗します。この場合の「内部」使用量は制限より少ない場合がありますが、断片化のために割り当てが失敗する可能性があることに注意してください。

また、外部メモリ追跡ツールを使用している場合、この環境変数_USE_ZEND_ALLOC=0_を設定すると、上記のメカニズムが無効になり、エンジンで常にmalloc()が使用されます。これによりパフォーマンスは大幅に低下しますが、malloc追跡ツールを使用できます。

このメモリマネージャに関する記事 も参照してください。コード例もあります。

45
StasM

memory_get_usage()も安全だと思いますが、両方の方法を比較して自分で決めることができると思います。システムコールを解析する関数を次に示します。

function Memory_Usage($decimals = 2)
{
    $result = 0;

    if (function_exists('memory_get_usage'))
    {
        $result = memory_get_usage() / 1024;
    }

    else
    {
        if (function_exists('exec'))
        {
            $output = array();

            if (substr(strtoupper(PHP_OS), 0, 3) == 'WIN')
            {
                exec('tasklist /FI "PID eq ' . getmypid() . '" /FO LIST', $output);

                $result = preg_replace('/[\D]/', '', $output[5]);
            }

            else
            {
                exec('ps -eo%mem,rss,pid | grep ' . getmypid(), $output);

                $output = explode('  ', $output[0]);

                $result = $output[1];
            }
        }
    }

    return number_format(intval($result) / 1024, $decimals, '.', '');
}
8
Alix Axel

xdebug を使用します。これは最近(29日1月)更新され、メモリプロファイリング情報が含まれるようになりました。関数呼び出しとそれらが消費するメモリ量を追跡します。これにより、コードに対する非常に洞察力のあるビューを取得でき、少なくとも問題を認識する方向に設定できます。

ドキュメントは役立ちますが、基本的には、インストールしてプロファイルを有効にしますxdebug.profiler_enable = 1と出力xdebug.profiler_output_dir=/some/pathqcachegrind などのツールを使用して、手作業を行い、視覚的に確認できるようにします。

1
SeanDowney