我有一個腳本,每天晚上從一個cron作業運行。最近幾分鐘後,它開始完全凍結,我不知道爲什麼。如果這是Java,我可以簡單地運行kill -3 PID
,它會在stdout中打印一個線程轉儲。在PHP中是否有任何等價物,我可以在正在運行的PHP腳本中獲取當前堆棧跟蹤(理想情況下是內存信息)的轉儲?獲取掛起的PHP腳本的堆棧跟蹤
回答
您可以做的最好的事情是在configure
期間使用--enable-debug
自己編譯PHP。如果進程則仍然掛起,您可以使用gdb的一些宏使用這些步驟獲得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二進制文件,--enable-debug
確保。
如果PHP腳本超過最大運行時間,它應該超時。那肯定會爲你解決問題;只是等待它破壞,並且有你的堆棧跟蹤。
我想你可能已經在你的代碼(或php.ini)中設置了最大運行時間爲零來阻止它中斷。如果你已經得到了這個,然後擺脫它(或者如果默認值太小,將其設置爲非常大的超時)。
您可能還想嘗試使用xDebug或類似的工具來運行它,它會爲您提供一個配置文件跟蹤,該配置文件跟蹤將爲您提供該程序的調用樹,並且還允許您單步執行IDE中的代碼,所以你可以看到到底發生了什麼;如果在那裏有一個無限循環,你應該能夠從中很快識別出它。
這是一個長時間運行的腳本。有時可能需要幾個小時。我經常重置超時的數量,這對於正在運行的函數來說是合理的,但是這種方式不能解決我的問題。 –
我注意到有一個可能的解決方案使用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__');
}
這*可能*工作,如果你不能添加' - 調試-enable'標誌到配置腳本。但是如果你不能使用配置增強功能,我認爲你不會進行這種調試。 –
只要你有安裝了PHP的gdb調試符號,你可以得到一個完整的PHP回溯。
安裝調試符號的方法從發行版到發行版可能有所不同。例如在亞馬遜Linux上,我運行rpm -qa | grep php56-common
並將結果傳遞給debuginfo-install
。請注意,使用標準軟件包管理器安裝調試符號可能無法提供預期的結果 - 在亞馬遜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
然後將這個小腳本:
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的內部,所以它可能不是更早或更晚版本。我用php 5.6.14做了這個。這種方法的優點是它可以同時運行進程和核心轉儲,而且不必重新編譯PHP或重新啓動PHP腳本。您甚至可以在之後安裝gdb和調試符號,您會發現掛起過程。
- 1. 獲取堆棧跟蹤參數的值?
- 2. 獲取在GDB中運行的掛起進程的堆棧跟蹤
- 3. 禁用PHP堆棧跟蹤
- 4. 提取從堆棧跟蹤
- 5. 從ZendFramework獲取完整堆棧跟蹤
- 6. 在VB6中獲取堆棧跟蹤
- 7. 從NullPointerException獲取堆棧跟蹤
- 8. 如何獲取堆棧跟蹤信息?
- 9. 從堆棧跟蹤獲取文件名
- 10. 在Perl中獲取堆棧跟蹤?
- 11. 使用cx_freeze獲取Python堆棧跟蹤
- 12. 從Visual Studio中獲取堆棧跟蹤
- 13. 獲取堆棧跟蹤不通過USB
- 14. 如何獲得正確的堆棧跟蹤而不是反射堆棧跟蹤?
- 15. 堆棧跟蹤3
- 16. eclipse中的堆棧跟蹤
- 17. 堆棧跟蹤的UserWarning
- 18. Objective-C的堆棧跟蹤
- 19. VB6中的堆棧跟蹤
- 20. ICS上的本機堆棧跟蹤?
- 21. 堆棧跟蹤如何構建以及堆棧如何跟蹤?
- 22. 從javascript堆棧跟蹤中查找Java實際堆棧跟蹤
- 23. 展開PHP堆棧跟蹤參數
- 24. 傳統GDB腳本中堆棧跟蹤的停止條件
- 25. 在gremlin-groovy腳本中獲取行號或完整堆棧跟蹤例外
- 26. 見futex的掛Python中的堆棧跟蹤(...,FUTEX_WAIT_BITSET_PRIVATE | ...)
- 27. 在堆棧跟蹤中捕獲FileNotFound?
- 28. Java - 捕獲所有堆棧跟蹤
- 29. 如何獲得堆棧跟蹤
- 30. 輕鬆獲得堆棧跟蹤
簡單的解決方案,將一些日誌語句放入您的代碼並查看它們停止執行的位置。 – Sammitch