strace 追蹤系統調用,ltrace 追蹤動態庫函數調用 (libc、libm、PHP 擴展 .so)。當 PHP 代碼邏輯看似無誤但性能異常,ltrace 能直擊 C 層熱點。本文通過一個 in_array 字符串轉長整型的實戰案例演示全流程。
<?php
// test.php
$y = '1380';
$arr = [];
for ($i = 0; $i < 2000; $i++) {
$arr[] = "{$i}"; // 故意存字符串
}
for ($i = 0; $i < 2000; $i++) {
if (!in_array($y, $arr)) continue;
}
執行極慢,CPU 100%,邏輯簡單卻跑不快。
ltrace -c /usr/local/php/bin/php test.php
# -c 統計匯總模式,輸出函數級耗時排名
輸出:
% time seconds usecs/call calls function
------ --------- ---------- ------ --------------------
95.02 7.417240 368 20146 strtol
2.15 7.160390 413 17316 memcpy
1.63 5.522641 240 22966 free
0.67 2.275374 2275374 1 curl_global_cleanup
0.54 2.235466 617 3618 __ctype_tolower_loc
0.16 2.123547 1194 1778 strrchr
0.17 1.532224 67 22836 malloc
0.29 0.382083 67 5678 strlen
strtol 佔 95% 時間,調用 20,146 次。in_array 非嚴格模式 ($strict=false 默認) 比較字符串 '1380' 與整數 1380 時,會嘗試將字符串轉換為長整型 (strtol) 再比較。in_array 遍歷 2000 元素 = 400 萬次比較,每次觸發 strtol。<?php
// 修正:存整數,避免類型轉換
$arr = [];
for ($i = 0; $i < 2000; $i++) {
$arr[] = $i; // 整數
}
// 或嚴格模式:in_array($y, $arr, true) 但 $y 仍需是整數
$y = 1380;
優化後執行時間從秒級降至毫秒級,ltrace -c 顯示 strtol 調用歸零。
| 參數 | 說明 |
|---|---|
-c | 統計匯總 (函數、調用次數、耗時、平均耗時) |
-S | 同時顯示系統調用 (strace+ltrace 合體) |
-f | 跟蹤子進程 (php-fpm worker、fork 進程) |
-p PID | 附加到運行中進程 (生產環境非侵入式分析) |
-e func1,func2 | 只追蹤指定函數 (如 -e malloc,free,strtol) |
-o output.txt | 輸出到文件 |
-T | 顯示每次調用耗時 (非匯總模式) |
strtol, strtod, zend_strtod (浮點解析)。malloc, free, realloc, emalloc, efree (Zend MM)。memcpy, memmove, strlen, strcmp, zend_hash_* (數組/HashTable 底層)。pcre_exec, pcre_compile (PCRE 庫)。php_json_encode, php_json_decode (php_json 擴展)。php_var_serialize, php_var_unserialize。# 1. ltrace 定位熱點函數
# 2. gdb 附加查看調用棧
gdb -p $(pgrep -f "php test.php")
(gdb) bt
# 3. perf 采樣分析 (需內核支持)
perf record -g -p $(pgrep -f "php test.php") -- sleep 10
perf report
ltrace -c 是 PHP 性能分析的「X 光機」:無需修改代碼、無需重編譯、無需埋點,一條命令直擊 C 層熱點。養成「代碼邏輯看不出問題 → ltrace 跑一遍」的肌肉記憶,能解決 80% 的「莫名其妙慢」疑難雜症。