突然之间,我的应用程序出现了前所未有的问题。我决定检查Apache的错误日志,并发现一条错误消息,指出“ zend_mm_heap已损坏”。这是什么意思。
操作系统:Fedora Core 8 Apache:2.2.9 PHP:5.2.6
突然之间,我的应用程序出现了前所未有的问题。我决定检查Apache的错误日志,并发现一条错误消息,指出“ zend_mm_heap已损坏”。这是什么意思。
操作系统:Fedora Core 8 Apache:2.2.9 PHP:5.2.6
Answers:
经过多次试验和错误,我发现如果我增加output_buffering
php.ini文件中的值,此错误就消失了
这不是必须通过更改配置选项解决的问题。
更改配置选项有时会产生积极的影响,但它很容易使情况变得更糟,或者什么也不做。
错误的性质是这样的:
#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
如果您不知道,您已经知道这mem
是堆分配的内存。堆是指程序在运行时可用的内存区域,因为程序显式地请求了它(在本例中为malloc)。
如果您使用糟糕的代码,则会发现并非所有那些显然不正确的语句都导致分段错误(致命的终止错误)。
我在示例代码中明确地犯了这些错误,但是在内存托管环境中很容易发生相同类型的错误:例如,如果某些代码不能以正确的方式维护变量(或其他符号)的引用计数如果释放的时间过早,则可能会从已经释放的内存中读取另一段代码,如果它以某种方式存储了错误的地址,那么另一段代码可能会写入无效的内存中,可能会被释放两次...
这些不是可以用PHP调试的问题,它们绝对需要内部开发人员的注意。
行动过程应该是:
可能没有任何利润...一开始我曾说过,您可能可以找到一种通过弄乱配置来改变症状的方法,但是这是千载难逢的机会,对您下次的使用无济于事同zend_mm_heap corrupted
一条消息,只有这么多的配置选项。
当发现错误时,我们必须创建错误报告,这一点非常重要,我们不能假设下一个遇到该错误的人将要去做……如果您使错误解决方案更实际,那么实际解决方案绝不会变得神秘。正确的人意识到这个问题。
如果您USE_ZEND_ALLOC=0
在环境中进行设置,则会禁用Zend自己的内存管理器;Zend的内存管理器确保每个请求都有自己的堆,在请求结束时释放所有内存,并针对仅适合PHP大小的内存块分配进行了优化。
禁用它会禁用那些优化,更重要的是,这可能会导致内存泄漏,因为有很多扩展代码依赖Zend MM在请求结束时(tut,tut)为其释放内存。
它也可能隐藏这些症状,但是系统堆可能以与Zend堆完全相同的方式损坏。
这可能似乎更宽容或不宽容,但解决问题的根本原因,它不能。
完全禁用它的功能是为了内部开发人员的利益。你应该永远禁用Zend的MM部署PHP。
我在PHP 5.5下遇到了同样的错误,增加输出缓冲并没有帮助。我也没有运行APC,所以这不是问题。我最终将其跟踪到opcache,只需要从cli禁用它即可。有一个特定的设置:
opcache.enable_cli=0
一旦切换,zend_mm_heap损坏的错误就消失了。
如果您在Linux机器上,请在命令行上尝试
export USE_ZEND_ALLOC=0
/etc/apache2/envvars
如果您是在ubuntu服务器上运行此程序,并且同时从ppas(apt)安装了apache和php,请记住将其添加到该行。当我从ondrej的存储库安装它时,PHP 7.0-RC4开始引发此错误。
set USE_ZEND_ALLOC=0
检查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
到目前为止,这似乎可行。
我正在将PHP 5.6与PHP-FPM和Apache proxy_fcgi一起使用,如果那很重要的话...
根据错误跟踪器,设置opcache.fast_shutdown=0
。快速关机使用Zend内存管理器清理其混乱情况,从而禁用该功能。
我认为这里没有答案,因此我将补充我的经验。我看到了相同的错误以及随机的httpd segfaults。这是一台cPanel服务器。有问题的症状是apache会随机重置连接(Chrome中未接收到任何数据,或者在Firefox中重置了连接)。这些似乎是随机的-大多数情况下它起作用,有时却没有。
当我到达现场时,输出缓冲已关闭。通过读取暗示输出缓冲的线程,我将其打开(= 4096)以查看会发生什么。此时,他们都开始显示错误。很好,因为现在错误可以重复了。
我经历了并开始禁用扩展。其中包括eaccellerator,pdo,ioncube loader和许多看起来令人怀疑的东西,但没有帮助。
我终于找到了顽皮的PHP扩展名“ homeloader.so”,它似乎是某种cPanel-easy-installer模块。删除后,我没有遇到任何其他问题。
在此注释上,这似乎是一条通用错误消息,因此您的里程会因所有这些答案而有所不同,您可以采取的最佳行动方案是:
未能通过以上所有操作,您还可以尝试以下操作:
祝好运。
我为这个问题努力了一个星期,这对我有用,或者至少对我有用
在进行php.ini
这些更改
report_memleaks = Off
report_zend_debug = 0
我的设置是
Linux ubuntu 2.6.32-30-generic-pae #59-Ubuntu SMP
with PHP Version 5.3.2-1ubuntu4.7
这没用。
因此,我尝试使用基准脚本,并尝试记录脚本的挂起位置。我发现在错误发生之前,实例化了一个php对象,完成该对象应完成的操作花费了3秒钟以上的时间,而在之前的循环中,最多花费了0.4秒钟的时间。我多次运行了此测试,每次都相同。我以为我应该重用该对象,而不是每次都创建一个新对象(这里有很长的循环)。到目前为止,我已经对该脚本进行了十多次测试,并且内存错误已消失!
使用适用于PHP的Mongo 2.2驱动程序时出现此错误:
$collection = $db->selectCollection('post');
$collection->ensureIndex(array('someField', 'someOtherField', 'yetAnotherField'));
^^不工作
$collection = $db->selectCollection('post');
$collection->ensureIndex(array('someField', 'someOtherField'));
$collection->ensureIndex(array('yetAnotherField'));
^^工作!(?!)
foreach(selectCollection()->find()) { $arr = .. }
如果您正在使用特征,并且特征是在类之后加载的(即自动加载的情况),则需要事先加载特征。
https://bugs.php.net/bug.php?id=62339
注意:这个错误是非常非常随机的;由于它的性质。
对我来说,问题是使用pdo_mysql。查询返回1960结果。我试图返回1900条记录,并且可以正常工作。所以问题是pdo_mysql和太大的数组。我用原始的mysql扩展重写了查询,它起作用了。
$link = mysql_connect('localhost', 'user', 'xxxx') or die(mysql_error());
mysql_select_db("db", $link);
Apache没有报告任何先前的错误。
zend_mm_heap corrupted
zend_mm_heap corrupted
zend_mm_heap corrupted
[Mon Jul 30 09:23:49 2012] [notice] child pid 8662 exit signal Segmentation fault (11)
[Mon Jul 30 09:23:50 2012] [notice] child pid 8663 exit signal Segmentation fault (11)
[Mon Jul 30 09:23:54 2012] [notice] child pid 8666 exit signal Segmentation fault (11)
[Mon Jul 30 09:23:55 2012] [notice] child pid 8670 exit signal Segmentation fault (11)
对我来说,问题是memcached守护程序崩溃了,因为PHP已配置为将会话信息存储在memcached中。它吃了100%的cpu,表现怪异。memcached重新启动后,问题就消失了。
由于没有其他答案可以解决这个问题,所以当我不小心运行了无限循环时,我在php 5.4中遇到了这个问题。
可能对某些人有用的一些技巧
fedora 20,PHP 5.5.18
public function testRead() {
$ri = new MediaItemReader(self::getMongoColl('Media'));
foreach ($ri->dataReader(10) as $data) {
// ...
}
}
public function dataReader($numOfItems) {
$cursor = $this->getStorage()->find()->limit($numOfItems);
// here is the first place where "zend_mm_heap corrupted" error occurred
// var_dump() inside foreach-loop and generator
var_dump($cursor);
foreach ($cursor as $data) {
// ...
// and this is the second place where "zend_mm_heap corrupted" error occurred
$data['Geo'] = [
// try to access [0] index that is absent in ['Geo']
'lon' => $data['Geo'][0],
'lat' => $data['Geo'][1]
];
// ...
// Generator is used !!!
yield $data;
}
}
使用var_dummp()实际上不是错误,它只是为了调试而放置,将在生产代码上删除。但是发生zend_mm_heap的真实位置是第二位。
我在这里处于同样的情况,以上无济于事,更认真地检查我发现了我的问题,它在于将一些输出发送到缓冲区后尝试执行die(header()),在代码中执行此操作的人忘记了CakePHP资源并且没有做一个简单的“返回$ this-> redirect($ url)”。
试图重新发明油井,这就是问题所在。
我希望这可以帮助某人!
USE_ZEND_ALLOC=0
在错误日志中获取stacktrace并发现了bug/usr/sbin/httpd: corrupted double-linked list
,我发现注释了对我有用的opcache.fast_shutdown=1
东西。