Get a stack trace of a hung PHP script
Get a stack trace of a hung PHP script
I have a script that runs from a cron job every night. Recently, it has started totally freezing up after several minutes into the script, and I can't figure out why. If this was Java, I could simply run kill -3 PID
and it would print a thread dump in stdout. Is there any equivalent in PHP, where I could get a dump of the current stack trace (and ideally memory info) on a running PHP script?
Answer by Thomas Kekeisen for Get a stack trace of a hung PHP script
Yes. You can get a backtrace with debug_backtrace
. Also you may need memory_get_usage
.
Answer by SDC for Get a stack trace of a hung PHP script
A PHP script should timeout if it exceeds the maximum runtime. Surely that would solve the problem for you; just wait for it to break, and there's your stack trace.
I guess it's possible that you've got something in your code (or php.ini) that sets the max runtime to zero to stop it breaking. If you've got that, then get rid of it (or set it to a very large timeout if the default really is too small).
You might also want to try running it with xDebug or a similar tool, which will give you a profiler trace that will give you a call tree of the program, and also allow you to step through the code in your IDE, so you can see exactly what is happening; if there's an infinite loop in there, you ought to be able to identify it pretty quickly from that.
Answer by johannes for Get a stack trace of a hung PHP script
The best thing you can do is compile PHP yourself using --enable-debug
during configure
. If the process then still hangs you can use gdb and some macros to get a PHP-level stacktrace using these steps:
$ 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
And then debug ahead :-)
Note that for this to work you have to have a PHP binary with symbol information, --enable-debug
ensures that.
Answer by romaninsh for Get a stack trace of a hung PHP script
I've noticed that there is a possible solution using pcntl_signal. I haven't tried it myself, you can find some sample code here:
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__'); }
Answer by sqaxomonophonen for Get a stack trace of a hung PHP script
Provided you have gdb and debugging symbols for PHP installed, you can get a full PHP backtrace.
The method of installing debugging symbols may vary from distro to distro. For instance on Amazon Linux I ran rpm -qa | grep php56-common
and passed the result to debuginfo-install
. Note that installing debugging symbols using the standard package manager might not give the desired result - on Amazon Linux I got debugging symbols for a different version of PHP when running yum install php56-debuginfo
and gdb didn't like that.
If you have configured your machine to produce core dumps you don't even need the process to be running to get a backtrace. You can kill -ABRT $pid
and inspect the core dump later.
You can then start debugging a running process with gdb -p $pid
or a core dump with gdb /usr/bin/php $path_to_core_dump
.
Typing bt
will give you a C stack trace. This will sometimes be enough to give you a hint of what might be wrong. Ensure that debugging symbols are correctly installed; bt
should point at file names and line numbers in the PHP source code.
Now try p executor_globals.current_execute_data
. It should print something like $1 = (struct _zend_execute_data *) 0x7f3a9bcb12d0
. If so, it means gdb can inspect the internals of PHP.
Using a little Python scripting you can produce a full PHP backtrace. Type python-interactive
and then insert this tiny script:
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"))
Note that this method depends heavily on the internals of PHP, so it might not work on earlier or later versions. I did this with php 5.6.14. The advantage of this method is that it works for both running processes and core dumps, plus you don't have to recompile PHP or restart your PHP script. You can even go install gdb and debugging symbols after you discover a hanging process.
Fatal error: Call to a member function getElementsByTagName() on a non-object in D:\XAMPP INSTALLASTION\xampp\htdocs\endunpratama9i\www-stackoverflow-info-proses.php on line 72
0 comments:
Post a Comment