“ zend_mm_heap损坏”是什么意思


126

突然之间,我的应用程序出现了前所未有的问题。我决定检查Apache的错误日志,并发现一条错误消息,指出“ zend_mm_heap已损坏”。这是什么意思。

操作系统:Fedora Core 8 Apache:2.2.9 PHP:5.2.6


2
我曾经USE_ZEND_ALLOC=0在错误日志中获取stacktrace并发现了bug /usr/sbin/httpd: corrupted double-linked list,我发现注释了对我有用的opcache.fast_shutdown=1东西。
Spidfire

是的,这里也一样。另请参见stackoverflow.com/a/35212026/35946
lkraav '16

我使用Laravel也有同样的事情。我将一个类注入另一个类的构造函数中。我正在注入的类,正在注入被注入的类,基本上是创建导致堆问题的循环引用。
托马斯

1
重新启动Apache服务器以获得最快和临时的解决方案:)
Leopathu

Answers:


52

经过多次试验和错误,我发现如果我增加output_bufferingphp.ini文件中的值,此错误就消失了


59
增加到什么?为什么此更改会使此错误消失?
JDS 2012年

2
@JDS这个答案有助于解释什么是output_buffering以及为什么增加它可以帮助stackoverflow.com/a/2832179/704803
andrewtweber 2012年

8
@andrewtweber我知道ob是什么,我想知道dsmithers的回答中遗漏的具体细节,因为我有与op相同的错误消息。对于关闭:事实证明我的问题是与memcached有关的配置错误。不过谢谢!
JDS 2012年

@JDS什么是配置错误的设置?
凯尔·克罗宁

3
@KyleCronin我们的服务平台在生产中使用Memcache。但是,某些单个实例(非生产/沙箱,一次性购买)不使用内存缓存。在后一种情况下,我将配置从生产环境一次性复制到客户,并且memcache配置指示该环境中不可用的memcache服务器URI。我删除了该行并在应用程序中禁用了内存缓存,问题消失了。因此,长话短说,这是在特定环境中遇到的非常特定的问题,可能通常不适用。但是,自从您问到…
JDS 2012年

47

这不是必须通过更改配置选项解决的问题。

更改配置选项有时会产生积极的影响,但它很容易使情况变得更糟,或者什么也不做。

错误的性质是这样的:

#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调试的问题,它们绝对需要内部开发人员的注意。

行动过程应该是:

  1. http://bugs.php.net上打开错误报告
    • 如果您遇到段错误,请尝试提供回溯
    • 包括尽可能多的配置信息,尤其是在使用opcache include优化级别时。
    • 继续检查错误报告是否有更新,可能需要更多信息。
  2. 如果您已加载opcache,请禁用优化
    • 我没有选择opcache,它很棒,但是已知其中的一些优化会导致错误。
    • 如果这不起作用,即使您的代码速度可能较慢,也请尝试先卸载opcache。
    • 如果以上任何一项更改或解决了问题,请更新您的错误报告。
  3. 一次禁用所有不必要的扩展。
    • 开始分别启用所有扩展,并在每次配置更改后进行全面测试。
    • 如果找到问题扩展名,请使用更多信息更新错误报告。
  4. 利润。

可能没有任何利润...一开始我曾说过,您可能可以找到一种通过弄乱配置来改变症状的方法,但是这是千载难逢的机会,对您下次的使用无济于事同zend_mm_heap corrupted一条消息,只有这么多的配置选项。

当发现错误时,我们必须创建错误报告,这一点非常重要,我们不能假设下一个遇到该错误的人将要去做……如果您使错误解决方案更实际,那么实际解决方案绝不会变得神秘。正确的人意识到这个问题。

USE_ZEND_ALLOC

如果您USE_ZEND_ALLOC=0在环境中进行设置,则会禁用Zend自己的内存管理器;Zend的内存管理器确保每个请求都有自己的堆,在请求结束时释放所有内存,并针对仅适合PHP大小的内存块分配进行了优化。

禁用它会禁用那些优化,更重要的是,这可能会导致内存泄漏,因为有很多扩展代码依赖Zend MM在请求结束时(tut,tut)为其释放内存。

它也可能隐藏这些症状,但是系统堆可能以与Zend堆完全相同的方式损坏。

这可能似乎更宽容或不宽容,但解决问题的根本原因,它不能

完全禁用它的功能是为了内部开发人员的利益。你应该永远禁用Zend的MM部署PHP。


那么潜在的问题可能是您正在运行哪个版本的PHP?
Ishmael

@Ishmael是的,以及所有扩展的版本,因为警告可能来自扩展。
主教

2
这个答案似乎对我来说是最好的。我亲身经历了几次该问题,它总是与错误的扩展名有关(在我的情况下,是Enchant拼写库)。除了php本身以外,它还可能是一个恶劣的环境(lib版本不匹配,错误的依赖关系等)
Fractalizer

1
到目前为止,对于该问题以及其他许多类似问题的最佳答案
Nikita

这个答案确实具有指导意义,但我认为调试服务器核心不是应用程序开发人员的工作。的确,如果您具有完整的堆栈跟踪,这会更容易,但是下一步是什么呢?要求将其修复为请求请求吗?并非每个人都是开发者或能够理解像C这样的低级语言。事实恰恰相反。因此,最后我相信,开发人员一开始就不会犯内存管理错误会容易得多。正如您所建议的,这在opcache中很常见,但并不奇怪在所有模块中都不常见,因为您知道有些开发人员知道如何开发。
job3dot5

46

我在PHP 5.5下遇到了同样的错误,增加输出缓冲并没有帮助。我也没有运行APC,所以这不是问题。我最终将其跟踪到opcache,只需要从cli禁用它即可。有一个特定的设置:

opcache.enable_cli=0

一旦切换,zend_mm_heap损坏的错误就消失了。


同样的问题和解决方案!谢谢!
MauricioSánchez2014年

2
巨大的加1这个职位。我们尝试了所有方法,但最终,只有此方法有效。
Geoffrey Brier

7
我确定您知道cli是php的命令行版本,并且与apache web服务器使用的php模块无关,例如,我很好奇cli如何禁用opcache?(我假设这是在Web服务器上发生的)
BIOHAZARD

@BioHazard,除了cli之外,还有一个常规设置opcache.enable = 0。但这并不一定对案件
有所

这应该是该问题的公认答案。根据php.ini中的文档,提高output_buffering并不是解决问题的方法,因为这可能会对您的网站或应用程序产生负面影响。
BlueCola

41

如果您在Linux机器上,请在命令行上尝试

export USE_ZEND_ALLOC=0

这救了我!我将其添加到php-fpm服务文件中(系统覆盖)
fzerorubigd 2014年

这为我做到了。/etc/apache2/envvars如果您是在ubuntu服务器上运行此程序,并且同时从ppas(apt)安装了apache和php,请记住将其添加到该行。当我从ondrej的存储库安装它时,PHP 7.0-RC4开始引发此错误。
Pedro Cordeiro

它也可以在Windows上使用:set USE_ZEND_ALLOC=0
Nabi KAZ,

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等)都隐藏了问题。


6
我通过简单的html dom遇到了这个问题,并且从未设置的状态更改为$ simplehtmldom-> clear(),它解决了我的问题,谢谢!
alexkb

9

对我来说,以前的答案都无效,直到我尝试了:

opcache.fast_shutdown=0

到目前为止,这似乎可行。

我正在将PHP 5.6与PHP-FPM和Apache proxy_fcgi一起使用,如果那很重要的话...


1
在所有不同的情况下都有大量的“我也是”响应,但这似乎与我的配置最相似,而且发展迅速-这种确切的变化似乎消除了我的问题。
lkraav '16

6

就我而言,此错误的原因是其中一个数组变得非常大。我已将脚本设置为在每次迭代时重置数组,从而解决了问题。


这为我做到了-谢谢!我不认为垃圾收集器会释放循环引用的内存,所以我没有检查它。
半快

5

根据错误跟踪器,设置opcache.fast_shutdown=0。快速关机使用Zend内存管理器清理其混乱情况,从而禁用该功能。


此问题在我们的CentOS Linux版本7.2.1511,PHP 5.5.38中修复了“ zend_mm_heap损坏”的问题。现在,我们可以继续使用操作码缓存。没有它的昼夜。
理查德·金斯伯格

感谢您的提醒,这正是我的问题!
Weasler '17

4

我认为这里没有答案,因此我将补充我的经验。我看到了相同的错误以及随机的httpd segfaults。这是一台cPanel服务器。有问题的症状是apache会随机重置连接(Chrome中未接收到任何数据,或者在Firefox中重置了连接)。这些似乎是随机的-大多数情况下它起作用,有时却没有。

当我到达现场时,输出缓冲已关闭。通过读取暗示输出缓冲的线程,我将其打开(= 4096)以查看会发生什么。此时,他们开始显示错误。很好,因为现在错误可以重复了。

我经历了并开始禁用扩展。其中包括eaccellerator,pdo,ioncube loader和许多看起来令人怀疑的东西,但没有帮助。

我终于找到了顽皮的PHP扩展名“ homeloader.so”,它似乎是某种cPanel-easy-installer模块。删除后,我没有遇到任何其他问题。

在此注释上,这似乎是一条通用错误消息,因此您的里程会因所有这些答案而有所不同,您可以采取的最佳行动方案是:

  • 每次都使错误可重复(什么条件?)
  • 寻找共同因素
  • 有选择地禁用任何PHP模块,选项等(或者,如果您急于将其全部禁用,以查看是否有帮助,然后有选择地重新启用它们,直到再次崩溃)
  • 如果这样做没有帮助,那么许多答案都暗示它可以被释放代码。同样,关键是使错误在每个请求中都可重复,以便您可以缩小错误范围。如果您怀疑有一段代码正在执行此操作,那么在错误可重复之后,只需删除代码,直到错误停止即可。一旦停止,您就知道删除的最后一段代码是罪魁祸首。

未能通过以上所有操作,您还可以尝试以下操作:

  • 升级或重新编译PHP。希望修复引起您问题的所有错误。
  • 将您的代码移到另一个(测试)环境。如果这样可以解决问题,则发生了什么变化?php.ini选项?PHP版本?等等...

祝好运。


3

我为这个问题努力了一个星期,这对我有用,或者至少对我有用

在进行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秒钟的时间。我多次运行了此测试,每次都相同。我以为我应该重用该对象,而不是每次都创建一个新对象(这里有很长的循环)。到目前为止,我已经对该脚本进行了十多次测试,并且内存错误已消失!


1
这工作了一段时间,但错误又回来了。我该如何阻止呢?
山姆

对于使用MAMP PRO 2.1.1的mac mavericks来说,这同样适用于我。
MutantMahesh 2014年

此解决方案无法永久解决问题,我再次开始收到此错误。
MutantMahesh 2014年

7
当然,这只是关闭错误报告而不是解决问题吗?
罗伯特(Robert Went)2015年

2

查找使用缓冲的任何模块,然后有选择地禁用它。

我在CentOS 4.8上运行PHP 5.3.5,这样做之后,我发现eaccelerator需要升级。


2

我在自己拥有的服务器上也遇到了这个问题,根本原因是APC。我注释掉了php.ini文件中的“ apc.so”扩展名,重新加载了Apache,然后这些站点又恢复了。


2

我已经尝试了以上所有内容,并且zend.enable_gc = 0-唯一的配置设置对我有所帮助。

带有Suhosin-Patch(cli)的PHP 5.3.10-1ubuntu3.2(内置:2012年6月13日17:19:58)


2

使用适用于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')); 

^^工作!(?!)


这个答案帮助我调试了Mongo问题。在我的情况下,PHP 5.6 + Mongo 1.6.9驱动程序,从先前通过foreach(selectCollection()->find()) { $arr = .. }
Mihai MATEI

2

在PHP 5.3上,经过大量搜索,这是对我有用的解决方案:

我通过添加以下内容禁用了此页面的PHP垃圾收集

<? gc_disable(); ?>

到问题页面的末尾,使所有错误消失。

来源


2

我认为很多原因都可能导致此问题。在我的情况下,我为2个类命名相同的名称,一个将尝试加载另一个。

class A {} // in file a.php
class A // in file b.php
{
  public function foo() { // load a.php }
}

就我而言,这会导致此问题。

(使用laravel框架,实际运行php artisan db:seed)


1

我有同样的问题,当我为memcached会话使用session.save_path的IP错误时。将其更改为正确的IP可解决此问题。


1

如果您正在使用特征,并且特征是在类之后加载的(即自动加载的情况),则需要事先加载特征。

https://bugs.php.net/bug.php?id=62339

注意:这个错误是非常非常随机的;由于它的性质。


1

对我来说,问题是使用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)

1

“ zend_mm_heap损坏”表示内存管理有问题。可以由任何PHP模块引起。以我为例,安装APC可行。从理论上讲,其他软件包(例如eAccelerator,XDebug等)也可能会有所帮助。或者,如果您安装了那种模块,请尝试将其关闭。


1

我在写PHP扩展,也遇到这个问题。当我从扩展程序中调用带有复杂参数的extern函数时,会弹出此错误。

原因是我没有在extern函数中为参数(char *)分配内存。如果您正在编写相同的扩展名,请注意这一点。


0

对我而言,正是ZendDebugger导致了内存泄漏并导致MemoryManager崩溃。

我禁用了它,目前正在寻找更新的版本。如果找不到,我将切换到xdebug ...


0

因为我从未找到解决方案,所以决定升级LAMP环境。我使用PHP 5.3.x进入Ubuntu 10.4 LTS。这似乎已经解决了我的问题。


0

就我而言,我忘记了以下代码:

);

我到处玩耍,在这里和那里的代码中忘记了它-在某些地方我发生了堆损坏,有些情况只是普通的seg错误:

[2011年6月8日星期三17:23:21] [注意]子pid 5720退出信号分段错误(11)

我在Mac 10.6.7和xampp上。


0

我还注意到在运行旧代码时出现此错误和SIGSEGV,在使用旧代码的情况下,该代码在PHP 5.2+中运行时使用'&'显式强制引用。


0

设置

assert.active = 0 

在php.ini中对我有帮助(它关闭了php5UTF8库中的类型断言并zend_mm_heap corrupted消失了)



0

由于没有其他答案可以解决这个问题,所以当我不小心运行了无限循环时,我在php 5.4中遇到了这个问题。


0

可能对某些人有用的一些技巧

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的真实位置是第二位。


0

我在这里处于同样的情况,以上无济于事,更认真地检查我发现了我的问题,它在于将一些输出发送到缓冲区后尝试执行die(header()),在代码中执行此操作的人忘记了CakePHP资源并且没有做一个简单的“返回$ this-> redirect($ url)”。

试图重新发明油井,这就是问题所在。

我希望这可以帮助某人!

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.