35

私の専用サーバーには 32GB の RAM が搭載されており、メモリは常に増え続けており、毎日再起動する必要があります。これは私に顧客とお金を犠牲にしています。

メモリリークがどこにあるかを見つけるのに苦労しています。私がオンラインで見つけることができるのは、人々が「xdebugを使用してください」と言っているだけですが、メモリリークを見つけるためのxdebugチュートリアルを見つけることができませんでした. 関数呼び出しの前後に memory_get_usage を印刷しようとしましたが、それは正しい方法ですか?

私は多くの php スクリプトを実行しています - 訪問者からのものもあれば、cron ジョブからのものもあります - それらのどれがメモリリークを起こしているかを見つけてできるだけ早く修正する必要がありますが、特定の関数がメモリリークかどうか。

関数呼び出しの前後に memory_get_usage を印刷しようとしましたが、上昇しましたが、関数を複数回呼び出すと、それ以上上昇しません。誰かがこれを説明して、PHP関数にメモリリークがあるかどうかを簡単かつ簡単に判断する方法を教えてください。

4

4 に答える 4

28

さまざまなことを行うことができますが、最初にメモリ リークが発生しないようにする必要があります。

はっきりさせておきますが、PHP はスクリプト言語であり、長時間実行されるスクリプト用に設計されていないため、メモリ管理は市場で最高のものではありません。しかし、なぜそれが必要なのですか?その目的はリクエスト レベルで呼び出されることなので、その実行範囲は非常に小さくなります (2 ~ 3 秒以内)。他のすべてはバックグラウンドに配置する必要があります。

メモリリークに対して何ができますか?

  1. 5.4 より前のバージョンを使用している場合は、ガベージ コレクションが行われないため、サークル参照に注意する必要があります。

  2. スクリプトを継続的に実行する必要がある場合は、別のアプローチを検討してください。while(true)実装を試してみてください。ただし、スクリプトをラップsupervisor( http://supervisord.org ) し、終了後に呼び出されるようにしてください。そうすれば、メモリ リークが発生しないことを 100% 保証できます。

  3. xdebugスクリプトを 1 つずつプロファイリングして、どこで多くのメモリが消費されているかを調べるために使用できます。

  4. クラスが不要になった場合は、参照するすべての設定を解除するデストラクタを実装できます。

    public function __destruct(){
        $this->cleanup();
    }
    
    public function cleanup() {
        //cleanup everything from attributes
        foreach (get_class_vars(__CLASS__) as $clsVar => $_) {
            unset($this->$clsVar);
        }
    
        //cleanup all objects inside data array
        if (is_array($this->_data)) {
            foreach ($this->_data as $value) {
                if (is_object($value) && method_exists($value, 'cleanUp')) {
                    $value->cleanUp();
                }
            }
        }
    }
    
  5. ガベージ コレクションに関する PHP ドキュメントを読むhttp://us3.php.net/manual/en/features.gc.php

  6. unsetグローバル変数はガベージ コレクションされず、明示的にする必要があるため、避けてください。ZF や Symfony などのフレームワークを使用している場合は、機能が壊れてしまうため、使用できない可能性があります。

最後にもう一度強調しておきたいのは、PHP は長時間実行されるスクリプトには適していないということです。やるべきことがあり、それを継続的に実行する必要がある場合は、PHP でのメモリ リークに頭を悩ませるのではなく、時間をかけて JAVA や C# などのより洗練された言語を学習してください。

于 2013-04-26T17:26:28.637 に答える
6

私にとってかなりうまくいく方法を見つけました:

  1. 「 php-memprof 」エクステンションをインストールします。Ubuntuで実行できます:

    sudo pecl install memprof

  2. 「 google-perftools 」をインストールします。再びUbuntuの場合:

    sudo apt-get install google-perftools

  3. このコードをスクリプトの先頭に追加します。

    if (function_exists('memprof_enable')) {
        memprof_enable();
    }
    
  4. そして、このあたりの場所は、メモリリークを見つけると予想していました:

    if (function_exists("memprof_dump_pprof"))
    {
        $time = microtime(true);
        $f = fopen("/tmp/profile_$time.heap", "w");
        memprof_dump_pprof($f);
        fclose($f);
        echo "Memory profile dumped. ";
    }
    

    私の場合、100回実行ごとに大きなサイクルの中にありました。

  5. google-pprof2 つのメモリ ダンプを比較して実行します。

    google-pprof --web --base=/tmp/profile_17.heap /tmp/profile_18.heap
    

    これにより、ブラウザーで次のような svg 画像が開きます。

    ドキュメントからのサンプル

    内部の番号と名前の説明は、gperftools のドキュメントに記載されています

PS PHPレベルでリークを修正しても、インタープリターにメモリリークがないことは保証されません。私の場合、 sctipt を長期間再起動するだけで終わります。

于 2016-03-29T15:30:38.257 に答える
1

私はメモリ使用量の専門家ではありませんが、この方法は問題のあるスクリプトを検出するのに役立つかもしれません:

情報を取得する: 1. Apache アクセス ログ ファイルを使用する 2. 独自のメモリ使用ログ ファイルを作成する ( http://www.webhostingtalk.com/showthread.php?t=617742 )

メモリ使用量が上昇する時間を確認し、apache のアクセス ログと比較します。

少なくとも、使用量がゆっくりと一定に増加するのか、それとも特定の時点で開始するのかについての情報を提供します.

幸運を!

于 2013-05-03T14:33:11.553 に答える