bku*_*lyk 123 php heap fedora php-internals
突然之间,我的应用程序出现了问题,这是我以前从未遇到的问题.我决定检查Apache的错误日志,我发现一条错误消息"zend_mm_heap corrupted".这是什么意思.
操作系统:Fedora Core 8 Apache:2.2.9 PHP:5.2.6
小智 51
经过多次试验和错误,我发现如果我增加output_bufferingphp.ini文件中的值,这个错误就会消失
小智 46
我在PHP 5.5下得到了同样的错误,增加输出缓冲没有帮助.我没有运行APC,所以这不是问题.我终于将其追踪到opcache,我只需要从cli中禁用它.有一个特定的设置:
opcache.enable_cli=0
Run Code Online (Sandbox Code Playgroud)
切换后,zend_mm_heap损坏的错误就消失了.
Joe*_*ins 44
这不是通过更改配置选项必须解决的问题.
更改配置选项有时会产生积极影响,但它可以轻松地使事情变得更糟,或者根本不做任何事情.
错误的本质是这样的:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main(void) {
void **mem = malloc(sizeof(char)*3);
void *ptr;
/* read past end */
ptr = (char*) mem[5];
/* write past end */
memcpy(mem[5], "whatever", sizeof("whatever"));
/* free invalid pointer */
free((void*) mem[3]);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
上面的代码可以编译为:
gcc -g -o corrupt corrupt.c
Run Code Online (Sandbox Code Playgroud)
使用valgrind执行代码,您可以看到许多内存错误,最终导致分段错误:
krakjoe@fiji:/usr/src/php-src$ valgrind ./corrupt
==9749== Memcheck, a memory error detector
==9749== Copyright (C) 2002-2013, and GNU GPL'd, by Julian Seward et al.
==9749== Using Valgrind-3.10.1 and LibVEX; rerun with -h for copyright info
==9749== Command: ./corrupt
==9749==
==9749== Invalid read of size 8
==9749== at 0x4005F7: main (an.c:10)
==9749== Address 0x51fc068 is 24 bytes after a block of size 16 in arena "client"
==9749==
==9749== Invalid read of size 8
==9749== at 0x400607: main (an.c:13)
==9749== Address 0x51fc068 is 24 bytes after a block of size 16 in arena "client"
==9749==
==9749== Invalid write of size 2
==9749== at 0x4C2F7E3: memcpy@@GLIBC_2.14 (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==9749== by 0x40061B: main (an.c:13)
==9749== Address 0x50 is not stack'd, malloc'd or (recently) free'd
==9749==
==9749==
==9749== Process terminating with default action of signal 11 (SIGSEGV): dumping core
==9749== Access not within mapped region at address 0x50
==9749== at 0x4C2F7E3: memcpy@@GLIBC_2.14 (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==9749== by 0x40061B: main (an.c:13)
==9749== If you believe this happened as a result of a stack
==9749== overflow in your program's main thread (unlikely but
==9749== possible), you can try to increase the size of the
==9749== main thread stack using the --main-stacksize= flag.
==9749== The main thread stack size used in this run was 8388608.
==9749==
==9749== HEAP SUMMARY:
==9749== in use at exit: 3 bytes in 1 blocks
==9749== total heap usage: 1 allocs, 0 frees, 3 bytes allocated
==9749==
==9749== LEAK SUMMARY:
==9749== definitely lost: 0 bytes in 0 blocks
==9749== indirectly lost: 0 bytes in 0 blocks
==9749== possibly lost: 0 bytes in 0 blocks
==9749== still reachable: 3 bytes in 1 blocks
==9749== suppressed: 0 bytes in 0 blocks
==9749== Rerun with --leak-check=full to see details of leaked memory
==9749==
==9749== For counts of detected and suppressed errors, rerun with: -v
==9749== ERROR SUMMARY: 4 errors from 3 contexts (suppressed: 0 from 0)
Segmentation fault
Run Code Online (Sandbox Code Playgroud)
如果你不知道,你已经发现那mem是堆分配的内存; 堆指的是程序在运行时可用的内存区域,因为程序显式请求它(在我们的例子中使用malloc).
如果您使用可怕的代码,您会发现并非所有明显不正确的语句都会导致分段错误(致命的终止错误).
我在示例代码中明确地做了这些错误,但是在内存管理环境中很容易发生同样的错误:如果某些代码没有以正确的方式维护变量(或其他符号)的引用计数,例如如果它是免费的太早,另一段代码可能从已经免费的内存读取,如果它以某种方式存储地址错误,另一段代码可能写入无效内存,它可能是免费的两次...
这些不是可以在PHP中调试的问题,它们绝对需要内部开发人员的注意.
行动方针应该是:
可能没有任何利润...我在开始时说过,你可能会找到一种通过搞乱配置来改变症状的方法,但这是非常受欢迎和错过,并且在下次你有时没有帮助相同的zend_mm_heap corrupted消息,只有这么多的配置选项.
当我们发现错误时,我们创建错误报告非常重要,我们不能假设下一个遇到错误的人会去做...更可能的是,实际的解决方案绝不是神秘的,如果你做的话合适的人知道这个问题.
如果你USE_ZEND_ALLOC=0在环境中设置,这将禁用Zend自己的内存管理器; Zend的内存管理器确保每个请求都有自己的堆,所有内存在请求结束时都是空闲的,并且针对PHP的内存大小分配进行了优化.
禁用它将禁用这些优化,更重要的是它可能会造成内存泄漏,因为有很多扩展代码依赖于Zend MM在请求结束时为它们释放内存(tut,tut).
它也可能隐藏症状,但系统堆可能会以与Zend堆完全相同的方式被破坏.
它似乎更宽容或更不宽容,但修复问题的根本原因,它不能.
完全禁用它的能力是为了内部开发人员的利益; 永远不应该在Zend MM禁用的情况下部署PHP.
f.a*_*ian 22
检查unset()s.确保你没有unset()引用$this析构函数中的(或等价物),并且析构函数中的unset()s不会导致同一对象的引用计数降至0.我做了一些研究,发现通常会导致堆的内容腐败.
有关于zend_mm_heap损坏错误的PHP错误报告.有关[2011-08-31 07:49 UTC] f dot ardelian at gmail dot com如何重现它的示例,请参阅注释.
我有一种感觉,所有其他"解决方案"(更改php.ini,从源代码使用较少的模块编译PHP等)只是隐藏问题.
对我来说,以前的答案都没有奏效,直到我尝试:
opcache.fast_shutdown=0
Run Code Online (Sandbox Code Playgroud)
到目前为止似乎有效.
我正在使用PHP 5.6与PHP-FPM和Apache proxy_fcgi,如果这很重要......
| 归档时间: |
|
| 查看次数: |
157714 次 |
| 最近记录: |