Что означает «zend_mm_heap поврежден»


127

Внезапно у меня возникли проблемы с моим приложением, которых у меня никогда раньше не было. Я решил проверить журнал ошибок Apache и обнаружил сообщение об ошибке «zend_mm_heap поврежден». Что это значит.

ОС: Fedora Core 8 Apache: 2.2.9 PHP: 5.2.6


2
Раньше я USE_ZEND_ALLOC=0получал трассировку стека в журнале ошибок и обнаружил ошибку /usr/sbin/httpd: corrupted double-linked list, я обнаружил, что комментирование opcache.fast_shutdown=1сработало для меня.
Spidfire,

Да, здесь то же самое. Также см. Другой отчет ниже stackoverflow.com/a/35212026/35946
lkraav

У меня было то же самое с Laravel. Я внедрил класс в конструктор другого класса. Класс, который я вводил, вводил класс, в который он был введен, в основном создавая круговую ссылку, вызывающую проблему с кучей.
Thomas

1
Перезагрузите сервер Apache для самых быстрых и временных решений :)
Леопату

Ответы:


52

После долгих проб и ошибок я обнаружил, что если я увеличу output_bufferingзначение в файле php.ini, эта ошибка исчезнет.


59
Увеличить до чего? Почему это изменение устраняет эту ошибку?
JDS

2
@JDS, этот ответ помогает объяснить, что такое output_buffering и почему его увеличение может помочь stackoverflow.com/a/2832179/704803
andrewtweber

8
@andrewtweber Я знаю, что такое ob, мне было интересно узнать о конкретных деталях, которые не были включены в ответ dsmithers, поскольку у меня было то же сообщение об ошибке, что и у op. В заключение: оказалось, что моя проблема связана с неправильной настройкой, относящейся к memcached. Спасибо хоть!
JDS

@JDS какая неверно настроенная настройка?
Kyle Cronin

3
@KyleCronin наша сервисная платформа использует Memcache в производстве. Однако некоторые отдельные экземпляры - непроизводственные / песочницы, разовые экземпляры клиентов - не используют кэш памяти. В последнем случае у меня была конфигурация, скопированная из производственной среды в одноразовый заказчику, и конфигурация memcache указала URI сервера memcache, который был недоступен в этой среде. Я удалил строку и отключил кэш памяти в приложении, и проблема исчезла. Итак, короче говоря, очень специфическая проблема, встречающаяся в конкретной среде, которая может быть неприменима в целом. Но раз уж вы спросили ...
JDS

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
    • Если у вас есть segfault, попробуйте предоставить обратную трассировку
    • Включите столько информации о конфигурации, сколько считаете нужным, в частности, если вы используете opcache, включая уровень оптимизации.
    • Продолжайте проверять отчет об ошибке на наличие обновлений, может потребоваться дополнительная информация.
  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.

Это может показаться более терпимым или менее терпимым, но устранить основную причину проблемы он не может .

Возможность его вообще отключить предназначена для внутренних разработчиков; Никогда не следует развертывать PHP с отключенным Zend MM.


Итак, основная проблема может заключаться в том, какую версию PHP вы используете?
Ishmael

@Ishmael Да, а также версии всех расширений, так как предупреждение может возникнуть из-за расширения.
епископ

2
Этот ответ кажется мне лучшим. Я лично сталкивался с этой проблемой несколько раз, и она всегда была связана с неисправным расширением (в моем случае - с библиотекой орфографии Enchant). Помимо самого php, это также может быть плохая среда (несоответствие версии lib, неправильные зависимости и т. Д.)
Fractalizer

1
Безусловно, лучший ответ на этот вопрос, а также на многие другие подобные вопросы
Никита 웃

Этот ответ действительно поучителен, но я считаю, что отладка ядра сервера - не задача разработчика приложений. На самом деле это намного проще, если у вас есть полная трассировка стека, но что дальше? попросить исправить это по запросу на перенос? Не все являются девопами или способны понимать язык низкого уровня, такой как C. Верно и обратное. В конце концов, я считаю, что было бы намного проще, если бы разработчики вообще не допускали ошибок управления памятью. Что, как вы предлагаете, типично для opcache, но неудивительно, что не для всех модулей, потому что вы знаете, что некоторые разработчики умеют разрабатывать.
job3dot5

46

Я получал ту же ошибку в PHP 5.5, и увеличение буферизации вывода не помогло. Я тоже не использовал APC, так что проблема была не в этом. Я наконец отследил это до opcache , мне просто пришлось отключить его из cli. Для этого была особая настройка:

opcache.enable_cli=0

После переключения ошибка поврежденного zend_mm_heap исчезла.


Такая же проблема и решение здесь! Спасибо!
Маурисио Санчес,

2
Огромный плюс 1 за этот пост. Мы все перепробовали, но в итоге только это сработало.
Джеффри Брайер

7
Я уверен, что вы знаете, что cli - это версия php для командной строки, и она не имеет ничего общего с модулем php, используемым, например, с веб-сервером apache, и мне любопытно, как помогло отключение opcache с помощью cli? (Я предполагаю, что это происходит на веб-сервере)
BIOHAZARD

@BioHazard, кроме cli есть общая настройка opcache.enable = 0. Но это не помогает делу
Константин Иванов

Это должен быть принятый ответ на этот вопрос. Увеличение output_buffering не является ответом, поскольку это может иметь негативные побочные эффекты для вашего веб-сайта или приложения, согласно документации в php.ini.
BlueCola 02

41

Если вы используете Linux, попробуйте это в командной строке

export USE_ZEND_ALLOC=0

Это меня спасло! Я добавляю это в служебный файл php-fpm (переопределение systemd)
fzerorubigd

Это сделало это для меня. Не забудьте добавить эту строку, /etc/apache2/envvarsесли вы запускаете это на сервере ubuntu с установленными apache и php из ppas (apt). PHP 7.0-RC4 начал выдавать эту ошибку, когда я установил его из репозитория ondrej.
Педро Кордейро,

А также работает на windows:set USE_ZEND_ALLOC=0
Nabi KAZ

22

Проверить unset()s. Убедитесь, что вы не unset()ссылаетесь на $this(или эквиваленты) в деструкторах, и что unset()s в деструкторах не приводит к тому, что счетчик ссылок на один и тот же объект падает до 0. Я провел небольшое исследование и обнаружил, что обычно вызывает кучу коррупция.

Имеется отчет об ошибке PHP о повреждении zend_mm_heap . См. Комментарий [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

6

В моем случае причиной этой ошибки было то, что один из массивов становился очень большим. Я установил свой скрипт на сброс массива на каждой итерации, и это решило проблему.


Это помогло мне - спасибо! Я не думал, что сборщик мусора освободит память от циклической ссылки, поэтому не проверял.
половинчатый

5

В соответствии с трекером ошибок установите opcache.fast_shutdown=0. Быстрое завершение работы использует диспетчер памяти Zend для устранения беспорядка, это отключает это.


Это исправило "повреждение zend_mm_heap" в нашей версии CentOS Linux 7.2.1511, PHP 5.5.38. Теперь мы можем возобновить использование кеша опкодов. Ночью и днем ​​без этого.
Ричард Гинзберг

Спасибо за напоминание, это была моя проблема!
Weasler

4

Я не думаю, что здесь есть один ответ, поэтому добавлю свой опыт. Я видел ту же ошибку вместе со случайными ошибками httpd segfaults. Это был сервер cPanel. Рассматриваемый симптом заключался в том, что apache произвольно сбрасывал соединение (данные не получены в Chrome, или соединение было сброшено в firefox). Они казались случайными - в большинстве случаев это срабатывало, иногда - нет.

Когда я прибыл на сцену, буферизация вывода была ВЫКЛЮЧЕНА. Прочитав эту ветку, в которой говорилось о буферизации вывода, я включил ее (= 4096), чтобы посмотреть, что произойдет. На этом этапе все они начали показывать ошибки. Хорошо, что теперь ошибка повторялась.

Я прошел и начал отключать расширения. Среди них, eaccellerator, PDO, IonCube погрузчик, и много что посмотрел подозрение, но ни помогло.

Я наконец нашел непослушное расширение 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
Некоторое время это работало, но ошибка вернулась. Как мне это остановить?
sam

То же самое сработало для меня на Mac-индивидуалистах с MAMP PRO 2.1.1.
MutantMahesh

Это решение не устранило проблему навсегда, я снова получаю эту ошибку.
MutantMahesh

7
Конечно, это просто отключение сообщения об ошибках, а не устранение проблемы?
Роберт уехал

2

Найдите любой модуль, который использует буферизацию, и выборочно отключите его.

Я использую PHP 5.3.5 на CentOS 4.8, и после этого я обнаружил, что eaccelerator требует обновления.


2

У меня тоже была эта проблема на моем сервере, и основной причиной была APC. Я закомментировал расширение «apc.so» в файле php.ini, перезагрузил Apache, и сайты сразу же восстановились.


2

Я пробовал все, что описано выше, и zend.enable_gc = 0- единственный параметр конфигурации, который мне помог.

PHP 5.3.10-1ubuntu3.2 с Suhosin-Patch (cli) (построено: 13 июня 2012 г. 17:19:58)


2

У меня была эта ошибка при использовании драйвера Mongo 2.2 для PHP:

$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, сообщение о повреждении zend_mm_heap было выдано при повторении и запросе значений из массива, ранее заполненного черезforeach(selectCollection()->find()) { $arr = .. }
Mihai MATEI


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

У меня была такая же проблема, и когда у меня был неправильный IP-адрес для session.save_path для сеансов memcached. Изменение его на правильный 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 и тоже сталкиваюсь с этой проблемой. Когда я вызываю внешнюю функцию со сложными параметрами из своего расширения, появляется эта ошибка.

Причина в том, что я не выделяю память для параметра (char *) во внешней функции. Если вы пишете такое же расширение, обратите на это внимание.


0

Для меня именно ZendDebugger вызвал утечку памяти и привел к сбою MemoryManager.

Я отключил его и сейчас ищу более новую версию. Если не найду, перейду на xdebug ...


0

Поскольку я так и не нашел решения этой проблемы, я решил обновить свою среду LAMP. Я перешел на Ubuntu 10.4 LTS с PHP 5.3.x. Кажется, это решило проблему для меня.


0

В моем случае я забыл в коде следующее:

);

Я поигрался и кое-где забыл об этом в коде - в некоторых местах я получал повреждение кучи, в некоторых случаях просто простая ошибка сегмента:

[Ср, 8 июня, 17:23:21 2011] [уведомление] дочерний 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

Для меня проблема заключалась в сбое демона memcached, поскольку PHP был настроен для хранения информации о сеансе в memcached. Он ел 100% процессор и вел себя странно. После перезапуска memcached проблема исчезла.


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

У меня была такая же ситуация здесь, ничего из вышеперечисленного не помогло, и, более серьезно проверяя, я нахожу свою проблему, она состоит в том, что попробуйте do die (header ()) после отправки некоторого вывода в буфер, человек, который сделал это в коде, забыл о ресурсах CakePHP и не сделал простого "return $ this-> redirect ($ url)".

Проблема была в попытке заново изобрести колодец.

Я надеюсь, что это поможет кому-то!

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.