php “zend_mm_heap 损坏”是什么意思

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/2247977/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-25 05:43:34  来源:igfitidea点击:

What does "zend_mm_heap corrupted" mean

phpheapfedoraphp-internals

提问by bkulyk

All of the sudden I've been having problems with my application that I've never had before. I decided to check the Apache's error log, and I found an error message saying "zend_mm_heap corrupted". What does this mean.

突然之间,我的应用程序遇到了以前从未遇到过的问题。我决定检查 Apache 的错误日志,我发现一条错误消息说“zend_mm_heap 损坏”。这是什么意思。

OS: Fedora Core 8 Apache: 2.2.9 PHP: 5.2.6

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

采纳答案by dsmithers

After much trial and error, I found that if I increase the output_bufferingvalue in the php.ini file, this error goes away

经过多次尝试和错误,我发现如果我增加output_bufferingphp.ini 文件中的值,这个错误就会消失

回答by Justin MacLeod

I was getting this same error under PHP 5.5 and increasing the output buffering didn't help. I wasn't running APC either so that wasn't the issue. I finally tracked it down to opcache, I simply had to disable it from the cli. There was a specific setting for this:

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

opcache.enable_cli=0

Once switched the zend_mm_heap corrupted error went away.

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

回答by Joe Watkins

This is not a problem that is necessarily solvable by changing configuration options.

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

Changing configuration options will sometimes have a positive impact, but it can just as easily make things worse, or do nothing at all.

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

The nature of the error is this:

错误的性质是这样的:

#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;
}

The code above can be compiled with:

上面的代码可以编译成:

gcc -g -o corrupt corrupt.c

Executing the code with valgrind you can see many memory errors, culminating in a segmentation fault:

使用 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

If you didn't know, you already figured out that memis heap allocated memory; The heap refers to the region of memory available to the program at runtime, because the program explicitly requested it (with malloc in our case).

如果你不知道,你已经知道这mem是堆分配的内存;堆是指程序在运行时可用的内存区域,因为程序显式请求它(在我们的例子中使用 malloc)。

If you play around with the terrible code, you will find that not all of those obviously incorrect statements results in a segmentation fault (a fatal terminating error).

如果您使用糟糕的代码,您会发现并非所有这些明显不正确的语句都会导致分段错误(致命的终止错误)。

I explicitly made those errors in the example code, but the same kinds of errors happen very easily in a memory managed environment: If some code doesn't maintain the refcount of a variable (or some other symbol) in the correct way, for example if it free's it too early, another piece of code may read from already free'd memory, if it somehow stores the address wrong, another piece of code may write to invalid memory, it may be free'd twice ...

我在示例代码中明确地犯了这些错误,但在内存管理环境中很容易发生相同类型的错误:例如,如果某些代码没有以正确的方式维护变量(或某些其他符号)的引用计数如果它过早释放,另一段代码可能会从已经释放的内存中读取,如果它以某种方式存储了错误的地址,另一段代码可能会写入无效内存,它可能会被释放两次......

These are not problems that can be debugged in PHP, they absolutely require the attention of an internals developer.

这些都不是 PHP 可以调试的问题,它们绝对需要内部开发人员的注意。

The course of action should be:

行动方针应该是:

  1. Open a bug report on http://bugs.php.net
    • If you have a segfault, try to provide a backtrace
    • Include as much configuration information as seems appropriate, in particular, if you are using opcache include optimization level.
    • Keep checking the bug report for updates, more information may be requested.
  2. If you have opcache loaded, disable optimizations
    • I'm not picking on opcache, it's great, but some of it's optimizations have been known to cause faults.
    • If that doesn't work, even though your code may be slower, try unloading opcache first.
    • If any of this changes or fixes the problem, update the bug report you made.
  3. Disable allunnecessary extensions at once.
    • Begin to enable all your extensions individually, thoroughly testing after each configuration change.
    • If you find the problem extension, update your bug report with more info.
  4. Profit.
  1. http://bugs.php.net上打开错误报告
    • 如果您有段错误,请尝试提供回溯
    • 包含尽可能多的配置信息,特别是如果您使用 opcache 包含优化级别。
    • 继续检查错误报告以获取更新,可能需要更多信息。
  2. 如果您加载了 opcache,请禁用优化
    • 我不是在选择 opcache,它很棒,但已知其中一些优化会导致故障。
    • 如果这不起作用,即使您的代码可能较慢,也请先尝试卸载 opcache。
    • 如果其中任何一项更改或修复了问题,请更新您所做的错误报告。
  3. 立即禁用所有不必要的扩展。
    • 开始单独启用所有扩展,在每次配置更改后进行彻底测试。
    • 如果您找到问题扩展,请使用更多信息更新您的错误报告。
  4. 利润。

There may not be any profit ... I said at the start, you may be able to find a way to change your symptoms by messing with configuration, but this is extremely hit and miss, and doesn't help the next time you have the same zend_mm_heap corruptedmessage, there are only so many configuration options.

可能没有任何收益……我一开始就说过,你可能会通过乱配置来找到改变症状的方法,但是这是非常碰运气的,下次有帮助时也无济于事同样的zend_mm_heap corrupted消息,只有这么多配置选项。

It's really important that we create bugs reports when we find bugs, we cannot assume that the next person to hit the bug is going to do it ... more likely than not, the actual resolution is in no way mysterious, if you make the right people aware of the problem.

当我们发现错误时,我们创建错误报告非常重要,我们不能假设下一个遇到错误的人会这样做......更有可能的是,实际的解决方案并不神秘,如果你让正确的人意识到了这个问题。

USE_ZEND_ALLOC

USE_ZEND_ALLOC

If you set USE_ZEND_ALLOC=0in the environment, this disables Zend's own memory manager; Zend's memory manager ensures that each request has it's own heap, that all memory is free'd at the end of a request, and is optimized for the allocation of chunks of memory just the right size for PHP.

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

Disabling it will disable those optimizations, more importantly it will likely create memory leaks, since there is a lot of extension code that relies upon the Zend MM to free memory for them at the end of a request (tut, tut).

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

It may also hidethe symptoms, but the system heap can be corrupted in exactly the same way as Zend's heap.

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

It may seem to be more tolerant or less tolerant, but fix the root cause of the problem, it cannot.

它可能看起来更宽容或更少宽容,但解决问题的根本原因,它不能

The ability to disable it at all, is for the benefit of internals developers; You should neverdeploy PHP with Zend MM disabled.

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

回答by Hittz

If you are on Linux box, try this on the command line

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

export USE_ZEND_ALLOC=0

回答by f.ardelian

Check for unset()s. Make sure you don't unset()references to the $this(or equivalents) in destructors and that unset()s in destructors don't cause the reference count to the same object to drop to 0. I've done some research and found that's what usually causes the heap corruption.

检查unset()s。确保您没有unset()引用$this析构函数中的(或等效项),并且析构函数中的unset()s 不会导致对同一对象的引用计数降至 0。我做了一些研究,发现这通常是导致堆的原因腐败。

There is a PHP bug report about the zend_mm_heap corruptederror. See the comment [2011-08-31 07:49 UTC] f dot ardelian at gmail dot comfor an example on how to reproduce it.

有一个关于 zend_mm_heap 损坏错误的PHP 错误报告。有关[2011-08-31 07:49 UTC] f dot ardelian at gmail dot com如何重现它的示例,请参阅评论。

I have a feeling that all the other "solutions" (change php.ini, compile PHP from source with less modules, etc.) just hide the problem.

我有一种感觉,所有其他“解决方案”(更改php.ini、使用较少模块从源代码编译 PHP 等)只是隐藏了问题。

回答by Jesús Carrera

For me none of the previous answers worked, until I tried:

对我来说,以前的答案都不起作用,直到我尝试过:

opcache.fast_shutdown=0

That seems to work so far.

到目前为止,这似乎有效。

I'm using PHP 5.6 with PHP-FPM and Apache proxy_fcgi, if that matters...

我将 PHP 5.6 与 PHP-FPM 和 Apache proxy_fcgi 一起使用,如果这很重要...

回答by Piotr

In my case, the cause for this error was one of the arrays was becoming very big. I've set my script to reset the array on every iteration and that sorted the problem.

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

回答by Taco de Wolff

As per the bug tracker, set opcache.fast_shutdown=0. Fast shutdown uses the Zend memory manager to clean up its mess, this disables that.

根据错误跟踪器,设置opcache.fast_shutdown=0. 快速关机使用 Zend 内存管理器来清理它的混乱,这会禁用它。

回答by A.B. Carroll

I don't think there is one answer here, so I'll add my experience. I seen this same error along with random httpd segfaults. This was a cPanel server. The symptom in question was apache would randomly reset the connection (No data received in chrome, or connection was reset in firefox). These were seemingly random -- most of the time it worked, sometimes it did not.

我认为这里没有一个答案,所以我将添加我的经验。我看到了同样的错误以及随机的 httpd 段错误。这是一个 cPanel 服务器。有问题的症状是 apache 会随机重置连接(在 chrome 中没有收到数据,或者在 Firefox 中重置了连接)。这些看起来是随机的——大多数时候它有效,有时它没有。

When I arrived on the scene output buffering was OFF. By reading this thread, that hinted at output buffering, I turned it on (=4096) to see what would happen. At this point, they allstarted showing the errors. This was good being that the error was now repeatable.

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

I went through and started disabling extensions. Among them, eaccellerator, pdo, ioncube loader, and plenty that lookedsuspicion, but none helped.

我经历了并开始禁用扩展。其中,eaccellerator、pdo、ioncube loader 和很多看起来很可疑,但都没有帮助。

I finally found the naughty PHP extension as "homeloader.so", which appears to be some kind of cPanel-easy-installer module. After removal, I haven't experienced any other issues.

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

On that note, it appears this is a generic error message so your milage will vary with all of these answers, best course of action you can take:

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

  • Make the error repeatable (what conditions?) every time
  • Find the common factor
  • Selectively disable any PHP modules, options, etc (or, if you're in a rush, disable them all to see if it helps, then selectively re-enable them until it breaks again)
  • If this fails to help, many of these answers hint that it could be code releated. Again, the key is to make the error repeatable every requestso you can narrow it down. If you suspect a piece of code is doing this, once again, after the error is repeatable, just remove code until the error stops. Once it stops, you know the last piece of code you removed was the culprit.
  • 每次都使错误可重复(什么条件?)
  • 找到公因数
  • 有选择地禁用任何 PHP 模块、选项等(或者,如果您很着急,请将它们全部禁用以查看是否有帮助,然后有选择地重新启用它们,直到再次中断)
  • 如果这没有帮助,这些答案中的许多都暗示它可能与代码相关。同样,关键是使每个请求都可以重复错误,以便您可以缩小范围。如果您怀疑某段代码正在执行此操作,请再次在错误可重复后删除代码,直到错误停止。一旦它停止,您就会知道您删除的最后一段代码是罪魁祸首。

Failing all of the above, you could also try things like:

如果以上所有方法都失败,您还可以尝试以下操作:

  • Upgrading or recompiling PHP. Hope whatever bug is causing your issue is fixed.
  • Move your code to a different (testing) environment. If this fixes the issue, what changed? php.ini options? PHP version? etc...
  • 升级或重新编译 PHP。希望任何导致您的问题的错误都已修复。
  • 将您的代码移动到不同的(测试)环境。如果这解决了问题,那么发生了什么变化?php.ini 选项?PHP版本?等等...

Good luck.

祝你好运。

回答by sam

I wrestled with this issue, for a week, This worked for me, or atleast so it seems

我与这个问题搏斗了一个星期,这对我有用,或者至少看起来

In php.inimake these changes

php.ini做出这些改变

report_memleaks = Off  
report_zend_debug = 0  

My set up is

我的设置是

Linux ubuntu 2.6.32-30-generic-pae #59-Ubuntu SMP  
with PHP Version 5.3.2-1ubuntu4.7  

This didn't work.

这没有用。

So I tried using a benchmark script, and tried recording where the script was hanging up. I discovered that just before the error, a php object was instantiated, and it took more than 3 seconds to complete what the object was supposed to do, whereas in the previous loops it took max 0.4 seconds. I ran this test quite a few times, and every time the same. I thought instead of making a new object every time, (there is a long loop here), I should reuse the object. I have tested the script more than a dozen times so far, and the memory errors have disappeared!

所以我尝试使用基准脚本,并尝试记录脚本挂断的位置。我发现就在错误发生之前,一个 php 对象被实例化,完成该对象应该执行的操作需要 3 秒多的时间,而在之前的循环中最多需要 0.4 秒。我跑了好几次这个测试,每次都一样。我想与其每次都创建一个新对象(这里有一个很长的循环),我应该重用该对象。到目前为止我已经测试了十几次脚本,内存错误消失了!