xhprof 是facebook 开发的一个测试php性能的扩展,
xhprof不支持php7,代码已经几年没有更新过了, 由于Facebook的优化方向是HHVM,所以这个扩展可以预见不会再有官方维护了。
目前github上有一些个人维护的php7版本, 但是完成的质量都不高,存在各种坑,很不幸我们踩了一个: 内存泄漏
test环境之前安装的版本: https://github.com/RustJason/xhprof/tree/php7
之前用着一直好好的, 一经压测就完蛋了,原因就是内存泄漏。
用valgrind检测结果, 摘抄部分如下:
==19323== 32 bytes in 1 blocks are definitely lost in loss record 10 of 30==19323== at 0x4C2210C: malloc (vg_replace_malloc.c:195)==19323== by 0x7F76AA: __zend_malloc (zend_alloc.c:2853)==19323== by 0xA5B9534: zend_string_alloc (zend_string.h:121)==19323== by 0xA5B94DB: zend_string_init (zend_string.h:157)==19323== by 0xA5B9E3F: hp_begin (xhprof.c:1688)==19323== by 0xA5B7D4D: zif_xhprof_enable (xhprof.c:403)==19323== by 0xA5B9B68: hp_execute_internal (xhprof.c:1586)==19323== by 0x883CFC: ZEND_DO_FCALL_SPEC_HANDLER (zend_vm_execute.h:844)==19323== by 0x882A30: execute_ex (zend_vm_execute.h:417)==19323== by 0xA5B980C: hp_execute_ex (xhprof.c:1527)==19323== by 0x882B47: zend_execute (zend_vm_execute.h:458)==19323== by 0x82A134: zend_execute_scripts (zend.c:1427)...................等等...................==19323== LEAK SUMMARY:==19323== definitely lost: 192 bytes in 6 blocks==19323== indirectly lost: 0 bytes in 0 blocks==19323== possibly lost: 0 bytes in 0 blocks==19323== still reachable: 2,633 bytes in 26 blocks==19323== suppressed: 0 bytes in 0 blocks==19323== Reachable blocks (those to which a pointer was found) are not shown.==19323== To see them, rerun with: --leak-check=full --show-reachable=yes可以看到明显有内存泄漏: definitely lost: 192 bytes in 6 blocks 从上面的日志可以看出问题所在的调用栈:
xhprof_enable() -> hp_begin() -> zend_string_init() -> zend_string_alloc() -> __zend_malloc() -> malloc()
对着扩展的源码找一下问题出在哪:
static void hp_begin(long level, long xhprof_flags TSRMLS_DC) { ................something..................... BEGIN_PROFILING(&hp_globals.entries, zend_string_init(ROOT_SYMBOL, sizeof(ROOT_SYMBOL) - 1, 1), hp_profile_flag); return; ..............................这块申请了内存, 但是并没有进行释放!看了下代码这个问题有些复杂, 下面这个结构体是一个全局变量保存了所有php函数的调用栈, 以及每个函数用的时间、cpu使用等信息。zend_string 是用来保存函数名的,就是这一块的内存发生了泄漏。由于这是一个全局变量, 整体代码中这个结构体耦合非常高, 改起来不容易。
typedef struct hp_entry_t { zend_string *name_hprof; /* function name */ int rlvl_hprof; /* recursion level for function */ uint64 tsc_start; /* start value for TSC counter */ long int mu_start_hprof; /* memory usage */ long int pmu_start_hprof; /* peak memory usage */ struct rusage ru_start_hprof; /* user/sys time start */ struct hp_entry_t *prev_hprof; /* ptr to prev entry being profiled */ uint8 hash_code; /* hash_code for the function name */而且,这个版本完成的质量不高,其作者也在readme中提到” Please do not use this in an production env.生产环境勿用。代码简直没法看。”
所以我放弃直接修复这个版本的bug, 而选择寻找其他方案
在尝试解决问题的时候发现了一个扩展Tideways, 这是基于xhprof的二次开发版本,是一整套解决方案(包括xhprof,以及性能分析的图形化界面等等)。需要注意的是这是一个这是一个商业版本, 其中图形化性能分析工具是收费的, xhprof功能是免费的, 对我们来说已经够用了。
测试了一下:
用法与xhprof一样,功能没有问题,满足我们需求valgrind检测无内存泄漏压测内存未见异常。新闻热点
疑难解答
图片精选