2013-01-10 13 views
8

私は毎晩cronジョブから実行するスクリプトを持っています。最近、スクリプトに数分後に完全に凍結し始めました。その理由を理解することはできません。これがJavaの場合は、単にkill -3 PIDを実行して、stdoutにスレッドダンプを出力します。 PHPで実行中のPHPスクリプトに現在のスタックトレース(および理想的にはメモリ情報)のダンプを取得できる同等のものはありますか?ハングしたPHPスクリプトのスタックトレースを取得

+0

シンプルなソリューションでは、いくつかのロギングステートメントをコードにスローし、実行中のどこで停止するかを確認します。 – Sammitch

答えて

7

configureの間に--enable-debugを使用して自分でPHPをコンパイルすることをお勧めします。これはあなたが持って仕事をするためにことを

注:-)先

$ gdb -p $PHP_PID 
(gdb) bt  # Get a system-level stacktrace, might already give some info 
(gdb) source /path/to/php-src/.gdbinit # Load some useful macros 
(gdb) dump_bt executor_globals.current_execute_data 
      # Macro from PHP's .gbinit giving PHP stack trace 
      # If you for whatever reason are using a thread-safe PHP build you have to do this: 
(gdb) ____executor_globals 
(gdb) dump_bt $eg.current_execute_data 

そしてデバッグ:プロセスはその後、まだハングする場合は、これらの手順を使用してPHPレベルのスタックトレースを取得するには、GDBといくつかのマクロを使用することができますシンボル情報を持つPHPバイナリを使用するには、--enable-debugが必要です。

+0

こんにちは。同じ方法でPHP変数の現在の値を出力することは可能ですか? – shark555

+1

私の頭の上から:dump_ht executor_globals.active_symbol_table(使用する変数の名前を確認する:lxr.php.netまたはローカルのPHPソースツリーに行き、executor_globals定義を確認する) – johannes

+0

私はpthreads拡張子を使用していますPHPのマルチスレッド化)、これが機能するためにはスタックフレームに 'tsrm_ls'引数の値を指定してset_ts(else ____executor_globalsがクラッシュ)コマンドを最初に使用しなければなりませんでした。 – 2072

2

はい。あなたはdebug_backtraceとバックトレースを得ることができます。またmemory_get_usageが必要な場合もあります。

+2

私の問題は、どこにぶら下がっているのか分かりません。私がした場合、これは簡単な解決策になります。 –

1

PHPスクリプトは、最大実行時間を超えるとタイムアウトする必要があります。確かにそれはあなたのために問題を解決するでしょう。それが壊れるのを待って、あなたのスタックトレースがあります。

コード(またはphp.ini)に、最大実行時間をゼロに設定して中断させないようにしている可能性があります。あなたがそれを持っている場合は、それを取り除く(または、デフォルトが本当に小さすぎると非常に大きなタイムアウトに設定する)。

xDebugまたは同様のツールを使用して実行すると、プログラムの呼び出しツリーを表示するプロファイラトレースが表示され、IDEのコードをステップ実行することもできます。何が起こっているかを正確に見ることができます。そこに無限ループがある場合は、それをかなり素早く識別することができなければなりません。

+0

これは長時間実行されるスクリプトです。時には数時間かかることがあります。私は定期的に実行している機能のための合理的な量のタイムアウトをリセットしますが、これはどういうわけか私の問題をキャッチしません。 –

2

私はpcntl_signalを使用して解決策があることに気付きました。私はそれを自分で試したことがない、あなたはここでいくつかのサンプルコードを見つけることができます。

https://secure.phabricator.com/D7797

function __phutil_signal_handler__($signal_number) { 
    $e = new Exception(); 
    $pid = getmypid(); 
    // Some phabricator daemons may not be attached to a terminal. 
    Filesystem::writeFile(
    sys_get_temp_dir().'/phabricator_backtrace_'.$pid, 
    $e->getTraceAsString()); 
} 

if (function_exists('pcntl_signal')) { 
    pcntl_signal(SIGHUP, '__phutil_signal_handler__'); 
} 
+0

このオプションは '--debug configureスクリプトに-enableフラグを設定します。しかし、私はあなたがconfigure augmentsで遊ぶことができないなら、このレベルのデバッグをやっているとは思っていません。 –

1

インストールしたPHPのためのgdbとデバッグシンボルを持って提供は、あなたが完全なPHPバックトレースを取得することができます。

デバッグシンボルをインストールする方法は、ディストリビューションごとに異なる場合があります。たとえばAmazon Linuxではrpm -qa | grep php56-commonを実行し、結果をdebuginfo-installに渡しました。 AmazonのLinuxでは、yum install php56-debuginfoを実行しているときに、別のバージョンのPHP用のデバッグシンボルがあり、gdbはそれを好まなかったことに注意してください。

がある場合は、バックトレースを取得するためにプロセスを実行する必要はありません。 kill -ABRT $pidを実行し、後でコアダンプを調べることができます。

実行中のプロセスのデバッグをgdb -p $pidまたはgdb /usr/bin/php $path_to_core_dumpのコアダンプで開始できます。

btと入力すると、Cスタックトレースが得られます。これは時には間違っているかもしれないことのヒントを与えるのに十分です。デバッグシンボルが正しくインストールされていることを確認してください。 btは、PHPソースコードのファイル名と行番号を指す必要があります。

今すぐ試すp executor_globals.current_execute_dataそれは$1 = (struct _zend_execute_data *) 0x7f3a9bcb12d0のようなものを出力するはずです。もしそうなら、それはgdbがPHPの内部を検査できることを意味します。

小さなPythonスクリプトを使用すると、完全なPHPバックトレースを生成できます。 python-interactiveを入力してから、この小さなスクリプトを挿入します。この方法は、PHPの内部に大きく依存するので、それはそれ以前またはそれ以降のバージョンでは動作しない場合がありますことを

def bt(o): 
    if o == 0: return 
    print "%s:%d" % (o["op_array"]["filename"].string(), o["opline"]["lineno"]) 
    bt(o["prev_execute_data"]) 

bt(gdb.parse_and_eval("executor_globals.current_execute_data")) 

注意を。私はこれをPHP 5.6.14で行いました。この方法の利点は、実行中のプロセスとコアダンプの両方で動作し、PHPを再コンパイルしたり、PHPスクリプトを再起動する必要がないことです。また、の後にgdbをインストールして、デバッグシンボルを実行すると、ハングするプロセスが検出されます。

関連する問題