又一个PHP低概率Core的分析(PHP内存管理)
浏览:3430次 出处信息
一个同事forward过来一个, 公司某产品线遇到的一个低概率, 但长时间出现了几次的Core的bt信息, 找我帮忙分析下原因.
bt栈如下(路径信息以*代替):
以下是代码片段: #0 0x00000000004a75e5 in _zend_mm_alloc_int (heap=0xd61260, size=79) at /*/php-5.2.6/Zend/zend_alloc.c:1879 #1 0x000000000048d3cd in vspprintf (pbuf=0x7fbffe9cd8, max_len=1024, format=Variable "format" is not available. ) at /*/php-5.2.6/main/spprintf.c:224 #2 0x0000000000489747 in php_error_cb (type=1, error_filename=0x2a9a787ee8 "/*/application/helpers/util.php", error_lineno=1149, format=Variable "format" is not available. ) at /*/php-5.2.6/main/main.c:799 #3 0x000000000061db35 in soap_error_handler (error_num=1, error_filename=0x2a9a787ee8 "/*/application/helpers/util.php", error_lineno=1149, format=0x7b9cb8 "Maximum execution time of %d second%s exceeded", args=0x7fbffea3b0) at /*/php-5.2.6/ext/soap/soap.c:2178 #4 0x00000000004c2576 in zend_error (type=1, format=0x7b9cb8 "Maximum execution time of %d second%s exceeded") at /*/php-5.2.6/Zend/zend.c:976 #5 <signal handler called> #6 0x00000000004a720f in _zend_mm_free_int (heap=0xd61260, p=Variable "p" is not available. ) at /*/php-5.2.6/Zend/zend_alloc.c:844 ...以下省略 |
以下是代码片段: HANDLE_BLOCK_INTERRUPTIONS(); .... HANDLE_UNBLOCK_INTERRUPTIONS(); |
好吧, 不管他了, 那么这个core到底是怎么产生的呢?
首先要介绍下PHP内存管理中的核心结构zend_mm_heap, 如下图:
对于free_buckets来说, 它存储了所有小块内存的指针, 对应的通过一个free_bitmap来指明在free_buckets中, 那些索引是可用的(有实际内存),
然后, 在zend_mm_free_int的函数调用中, 在回收内存的时候, 如果发现内存相邻的内存是空闲的, 则会进行合并, 具体的逻辑:
以下是代码片段: HANDLE_BLOCK_INTERRUPTIONS(); heap->size -= size; next_block = ZEND_MM_BLOCK_AT(mm_block, size); if (ZEND_MM_IS_FREE_BLOCK(next_block)) { zend_mm_remove_from_free_list(heap, (zend_mm_free_block *) next_block); size += ZEND_MM_FREE_BLOCK_SIZE(next_block); } //以下省略 |
以下是代码片段: //有省略 prev->next_free_block = next; next->prev_free_block = prev; if (EXPECTED(ZEND_MM_SMALL_SIZE(ZEND_MM_FREE_BLOCK_SIZE(mm_block)))) { if (EXPECTED(prev == next)) { size_t index = ZEND_MM_BUCKET_INDEX(ZEND_MM_FREE_BLOCK_SIZE(mm_block)); if (EXPECTED(heap->free_buckets[index*2] == heap->free_buckets[index*2+1])) { //注意这一行 heap->free_bitmap &= ~(ZEND_MM_LONG_CONST(1) << index); } } } else if (UNEXPECTED(mm_block->parent != NULL)) { goto subst_block; } //有省略 |
问题就出在这里
当代码执行到这句的时候, 业务逻辑超时信号被触发, 导致这行代码没有被执行, 就转入了信号处理流程.
以下是代码片段: #4 0x00000000004c2576 in zend_error (type=1, format=0x7b9cb8 "Maximum execution time of %d second%s exceeded") at /*/php-5.2.6/Zend/zend.c:976 #5 <signal handler called> #6 0x00000000004a720f in _zend_mm_free_int (heap=0xd61260, p=Variable "p" is not available. ) at /*/php-5.2.6/Zend/zend_alloc.c:844 |
以下是代码片段: #0 0x00000000004a75e5 in _zend_mm_alloc_int (heap=0xd61260, size=79) at /*/php-5.2.6/Zend/zend_alloc.c:1879 #1 0x000000000048d3cd in vspprintf (pbuf=0x7fbffe9cd8, max_len=1024, format=Variable "format" is not available. ) |
从而导致在alloc_init中的逻辑, 段错误退出:
以下是代码片段: # define ZEND_MM_CHECK_BLOCK_LINKAGE(block) \ if (UNEXPECTED((block)->info._size != ZEND_MM_BLOCK_AT(block, ZEND_MM_FREE_BLOCK_SIZE(block))->info._prev) || \ UNEXPECTED(!UNEXPECTED(ZEND_MM_IS_FIRST_BLOCK(block)) && \ UNEXPECTED(ZEND_MM_PREV_BLOCK(block)->info._size != (block)->info._prev))) { \ zend_mm_panic("zend_mm_heap corrupted"); \ } |
其实, 在出core的时候, 业务逻辑已经超时出错了, 而这个core是PHP本身的一些特点造就的, 也不能算是PHP的bug(起码它有一个看似屏蔽信号的操作), 只能说, 低概率的事件吧…
建议继续学习:
- Linux内存点滴 用户进程内存空间 (阅读:11598)
- ps - 按进程消耗内存多少排序 (阅读:11356)
- Linux Used内存到底哪里去了? (阅读:10021)
- Linux操作系统的内存使用方法详细解析 (阅读:8921)
- linux内核研究笔记(一)内存管理 – page介绍 (阅读:8766)
- 几个内存相关面试题(c/c++) (阅读:8073)
- 深入理解Nginx之调试优化技巧 (阅读:6903)
- 内存越界的概念和调试方法 (阅读:6342)
- Innodb分表太多或者表分区太多,会导致内存耗尽而宕机 (阅读:6202)
- 必看!linux系统如何查看内存使用情况 (阅读:6203)
QQ技术交流群:445447336,欢迎加入!
扫一扫订阅我的微信号:IT技术博客大学习
扫一扫订阅我的微信号:IT技术博客大学习
<< 前一篇:FirePHP,给力的调试工具
后一篇:PHP数组交集的优化 >>
文章信息
- 作者:雪候鸟 来源: 风雪之隅
- 标签: Core 内存 内存管理
- 发布时间:2011-01-27 22:53:53
建议继续学习
近3天十大热文
- [69] Twitter/微博客的学习摘要
- [67] IOS安全–浅谈关于IOS加固的几种方法
- [65] 如何拿下简短的域名
- [65] android 开发入门
- [63] find命令的一点注意事项
- [62] Go Reflect 性能
- [61] 流程管理与用户研究
- [60] Oracle MTS模式下 进程地址与会话信
- [59] 图书馆的世界纪录
- [57] 读书笔记-壹百度:百度十年千倍的29条法则