“zend_mm_heap损坏”是什么意思USE_ZEND_ALLOC
突然之间,我的应用程序遇到了以前从未遇到过的问题。我决定检查Apache的错误日志,我发现一条错误消息“zend_mm_heap损坏”。这是什么意思。
OS: Fedora Core 8 Apache: 2.2.9 PHP: 5.2.6
突然之间,我的应用程序遇到了以前从未遇到过的问题。我决定检查Apache的错误日志,我发现一条错误消息“zend_mm_heap损坏”。这是什么意思。
OS: Fedora Core 8 Apache: 2.2.9 PHP: 5.2.6
经过反复试验,我发现如果我增加php.ini文件中的值,这个错误就会消失。output_buffering
这不是一个必须通过更改配置选项解决的问题。
更改配置选项有时会产生积极影响,但它很容易使事情变得更糟,或者什么都不做。
错误的性质是这样的:
#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;
}
上面的代码可以编译为:
gcc -g -o corrupt corrupt.c
使用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
如果您不知道,您已经知道这是堆分配的内存;堆是指程序在运行时可用的内存区域,因为程序显式请求它(在我们的示例中使用malloc)。mem
如果你玩弄可怕的代码,你会发现并非所有那些明显不正确的语句都会导致分段错误(致命的终止错误)。
我在示例代码中明确地犯了这些错误,但是在内存管理的环境中,同样的错误很容易发生:如果某些代码没有以正确的方式维护变量(或其他一些符号)的引用计数,例如,如果它过早地释放了它,另一段代码可能会从已经释放的内存中读取, 如果它以某种方式存储了错误的地址,另一段代码可能会写入无效的内存,它可能会被释放两次......
这些不是可以在PHP中调试的问题,它们绝对需要内部开发人员的注意。
行动方针应是:
可能没有任何利润...我在一开始就说过,你也许能够通过搞乱配置来找到一种方法来改变你的症状,但这是非常打击和错过的,并且下次你有相同的消息时无济于事,只有这么多的配置选项。zend_mm_heap corrupted
当我们发现错误时,我们创建错误报告非常重要,我们不能假设下一个击中错误的人会这样做......更有可能的是,如果你让合适的人意识到这个问题,实际的解决方案绝不是神秘的。
如果您在环境中设置,这将禁用Zend自己的内存管理器;Zend的内存管理器确保每个请求都有自己的堆,在请求结束时释放所有内存,并针对分配与PHP大小恰到好处的内存块进行了优化。USE_ZEND_ALLOC=0
禁用它将禁用这些优化,更重要的是它可能会产生内存泄漏,因为有很多扩展代码依赖于Zend MM在请求结束时为它们释放内存(tut,tut)。
它也可能隐藏症状,但系统堆的损坏方式可能与Zend的堆完全相同。
它可能看起来更宽容或更不宽容,但解决问题的根本原因,它不能。
完全禁用它的能力是为了内部开发人员的利益;您永远不应该在禁用 Zend MM 的情况下部署 PHP。