Неустранимая ошибка: нехватка памяти, но у меня много памяти (PHP)

Поскольку мой вопрос становится все длиннее и длиннее, я решаю переписать весь вопрос, чтобы сделать его лучше и короче.

Я запускаю свой сайт на выделенном сервере с 8 ГБ памяти. Я полностью осознаю, что мне нужно увеличить лимит памяти на настройке php.ini. Я установил его с 128M до 256M и до -1. Тем не менее проблема заключается в настойчивости.

Неустранимая ошибка: Недостаточно памяти (выделено 786432) (попытался выделить 24576 байт) в D: \ www \ football \ views \ main.php в строке 81

Недостаток памяти не имеет смысла, потому что он сказал, что выделено только 786432 байта, и ему нужно еще 24576 байт.

786432 байт составляет всего 768 килобайт и довольно мало.

Советы

  • Ошибка возникает на очень случайной строке. Это не всегда ошибка на линии номер 81.
  • В пиковое время Apache занимает всего 500 мб памяти. У меня все еще есть 6 ГБ.
  • Нет бесконечного цикла.
  • Сценарий занимает 1024 байта. Получение этого числа из echo memory_get_peak_usage();
  • Набор результатов из MySQL мал (не более 12 строк, чисто текстовых, без данных BLOB)
  • ( Важно ) Если я перезапускаю Apache один раз в два дня, ошибка исчезнет. Обычно это происходит, когда Apache работает более 2 дней.
  • Я включил профилирование скрипта, и вы можете получить его здесь .
  • Этот выделенный сервер используется исключительно для запуска только одного веб-сайта. Этот веб-сайт является веб-сайтом с высоким трафиком со скоростью в среднем 1000 посетителей каждую минуту. В пиковое время одновременно будет доступно от 1 700 до 2000 посетителей.

Спецификация сервера

ОС: Windows 2008 R2 64-бит
Процессор: Intel Core i5 – 4 ядра
ОЗУ: 8 ГБ
Apache 2.2
PHP 5.3.1
Хранение: жесткие диски 2 x 1 ТБ
Полоса пропускания: 10 ТБ в месяц

Решение

Я, наконец, настроил и исправил проблему, и я хотел бы поделиться ею здесь, что я сделал, чтобы улучшить:

  1. favicon.ico отсутствовал, что испортило мой механизм маршрута. Хотя мой механизм маршрутов очень мал, но, включив favicon.ico , он помогает сократить использование памяти, не запуская мой механизм маршрута. Большая часть моего сайта имеет его, и я забыл поставить его для этого нового раздела.
  2. Ограничение MaxRequestPerChild помогает. На моем другом выделенном сервере у меня ограничен MaxRequestPerChild . Для этого сервера я установил его равным 0. Я всегда думал, что каждый сценарий изолирован. Допустим, если мой сценарий займет 800kb для запуска. По завершении Apache или PHP должны освободить память 800 КБ. Похоже, что так не получается. Ограниченный MaxRequestPerChild помогает предотвратить утечку памяти, создавая новый процесс после ограниченного MaxRequestPerChild и старый процесс умирает. Это моя новая настройка.

     ThreadsPerChild 1500 MaxRequestsPerChild 10000 
  3. ob_flush(); уменьшает немного больше памяти. Это не помогает, но помогает оптимизация.

  4. Я использовал xdebug который я никогда не использовал раньше, как это было предложено людьми, которые пытаются ответить на этот вопрос. Я должен сказать, что это отличный инструмент, и я оптимизировал несколько продуктов, чтобы заставить его работать немного быстрее.
  5. Я отключил несколько ненужных модулей Apache. Я пытаюсь отключить его один за другим и оставьте его на несколько дней, чтобы убедиться, что он работает отлично, прежде чем отключить другой. Теперь у меня есть все ненужное расширение PHP.
  6. Большая часть моего скрипта на этом сервере использовалась традиционным способом (без шаблона, без уровня базы данных, чистого PHP, HTML и старой функции mysql_ *). Честно говоря, он работает очень быстро и использует чрезвычайно маленькую память. Тем не менее, обслуживание сценария не очень просто, так как веб-сайт становится дольше. Я попытался преобразовать некоторые части веб-сайта в правильную структуру (моя собственная крошечная структура). Причина, по которой я использовал свои собственные фреймворки, потому что она крошечная (3kb для всей структуры и включает только то, что мне нужно).
  7. Переключение на IIS7.5 полностью решает эту проблему .

Я столкнулся с такой же проблемой, когда сервер умирал при попытке использовать своп. Это связано с тем, что mod_php не освобождает память . Таким образом, процессы Apache продолжают расти либо до предела apache, либо из-за ограничения памяти PHP, или, если нет предела, сбой сервера.

Перезапуск apache заставляет его создавать новые свежие тонкие процессы, но со временем они запускают скрипты PHP, они растут до тех пор, пока не возникнут проблемы.

Решение состоит в том, чтобы заставить apache убивать процессы после того, как определенное количество запросов было выполнено, чтобы они создавали новые (есть некоторые вопросы, связанные с этим ), уменьшая параметр конфигурации MaxRequestsPerChild , скажем 100 (по умолчанию 1000).

Конечно, это может снизить производительность сервера, поскольку он требует ресурсов, чтобы убивать и запускать новые процессы, но по крайней мере он поддерживает работу сайта. У вас может возникнуть соблазн повысить количество запущенных процессов, чтобы поддерживать высокие показатели, убедитесь, что ограничение памяти PHP (или apache) x максимальное количество процессов не распространяется на физический RAM вашего сервера.

Вот мой опыт, надеюсь, что это поможет.

Для начала memory_get_peak_usage() не поможет. Он вернет только объем памяти, который был выделен, и это тот же номер, который вызвал ошибку.

memory_get_usage вернет активный объем памяти, который выделяется при его вызове.

ini_set('memory_limit', '256M'); будет устанавливать максимальный учет влияния PHP на ваши системы Memory. Если вы получаете OOM на 768K, то это не устранит проблему.

Нет никаких указаний относительно того, какую версию PHP вы используете, но я бы предложил обновление сразу. Есть несколько ошибок, из-за которых менеджер памяти Zend не может освободить память, что приведет вас к одной и той же проблеме.

Как ваш локальный сервер, так и ваш производственный сервер работают с той же версией ОС, такой же длинный бит и одна и та же версия PHP? Ответ будет отрицательным.

Если он не связан с проблемой windows malloc() , поскольку он является поддоменом и, вероятно, внутри VirtualHost и выделяет только 768k, это почти похоже на проблему с ОС.

Запуск tasklist из командной строки при доступе к скрипту. Вы видите дополнительный поток Apache или использование памяти во всплеске процессов?

Последняя идея – запустить flush() и / или ob_flush(); после каждого цикла для строки / столбца таблицы. Это должно очистить ваш буфер и сохранить вам некоторую память в случае, когда это происходит.

Я бы начал с обновления PHP до 5.4+, так как это на 50% быстрее для некоторых приложений. Они зафиксировали большое количество утечек памяти. Пожалуйста, см. Becnhamrks: http://news.php.net/php.internals/57760

Установите xdebug и включите триггер профайлера. Создайте файл профилировщика, а затем опубликуйте файл cachegrind, если вы все еще не сможете сообщить об источнике проблемы.

EDIT: файл профилирования страницы, где происходит утечка памяти!

Обратите внимание, что ошибка имеет недостаток Out of memory и не Allowed memory size [..] exhausted .

Таким образом, утечка памяти находится в другом месте системы. Возможно, сервер mysql использует много системной памяти после этого тяжелого запроса, оставив apache / php без физического и свопового обмена.

Это должно объяснять ошибку всегда в одной строке (и / или в том же скрипте).

Я бы предположил, что вы либо не отредактировали правильный php.ini либо не перезапустили PHP и / или веб-сервер.

Создайте страницу phpinfo.php в своем docroot с содержимым <?php phpinfo(); чтобы убедиться, что вы меняете правильный php.ini . В дополнение к местоположению файла php.ini который использует веб-сервер, он также укажет допустимую максимальную память сценария.

Затем я добавлю несколько следов стека на вашу страницу, чтобы вы могли видеть цепочку событий, которые привели к этому. Следующая функция будет улавливать фатальные ошибки и предоставлять дополнительную информацию о том, что произошло.

 register_shutdown_function(function() { if($error = error_get_last()) { // Should actually log this instead of printing out... var_dump($error); var_dump(debug_backtrace()); } }); 

Лично, Nginx + PHP-FPM – это то, что я использовал в течение многих лет с тех пор, как я ушел из медленного Apache.

Эй, у меня тоже такая же проблема на моем сервере. Я просто изменил следующее:

измените php.ini на …

 memory_limit = 128M 

и добавьте httpd.conf

 RLimitMEM 1073741824 2147483648 

и перезапустите apache и я удалил ошибку:

Может возникнуть проблема с MySQL и количеством открытых подключений, следовательно, почему он сортируется, когда вы перезапускаете каждые несколько дней. Они автоматически закрываются при завершении работы скрипта?

Просто повторю (я добавляю этот ответ на достаточное расстояние от исходного вопроса):

  • PHP не может выделить то, что кажется небольшим объемом памяти
  • текущее использование памяти в то время, когда ошибка occrs + запрашиваемая сумма меньше существующего в настоящее время предела памяти
  • система имеет 6Gb, доступную для использования PHP, когда это происходит
  • поскольку проблема решена путем перезапуска apache – это apache, который препятствует доступности памяти из PHP для PHP

Если все они действительны, то единственно возможным объяснением является то, что 6Gb очень фрагментирован, что, я думаю, маловероятно. Вы не сказали, как PHP вызывается из Apache – mod_php? FPM? FCGI?

Я бы начал с изучения каждого из вышеперечисленных предикатов, в частности, свободной памяти. Откуда вы знаете, что при ошибке возникает 6Gb? Более вероятная причина в том, что происходит утечка памяти, которую вы не заметили.

Вы не указали какие-либо сведения о настройке apache; Я бы также посмотрел на сокращение MaxRequestsPerChild и MaxMemFree. (Я не очень хорошо знаком с рабочим apache, где это применимо для каждого потока – вам действительно нужно ограничение на процесс). Если вы предоставили базовую настройку из конфигурации apache, возможно, мы могли бы сделать дополнительные предложения.

Если вы не используете Ajax экстенсивно, убедитесь, что ваше время ожидания составляет 2 или меньше.

Следующие два факта определенно указывают на утечки памяти:

  1. Ошибка отображается в разных строках вашего кода,
  2. Ошибка сообщает об относительно небольшом распределении памяти.

Сначала я бы выделил PDO, отключив все остальные расширения и позвонил ему в одночасье, используя что-то вроде Siege / Apache Bench (ab). Вы также можете попробовать запустить его с помощью интерфейса cli (просто убедитесь, что вы сохраняете одинаковые пределы памяти).

Вы можете использовать memory_get_peak_usage() в конце вашего скрипта, чтобы узнать, сколько памяти PHP думает, что она использует.

Из вашего комментария это 800 kB, что хорошо; определенно не гигантский объем памяти, который мог бы вызвать нехватку памяти 😉

Наконец, хотя я бы не рекомендовал обновление до 5.4 на данный момент, обновление до последнего 5.3.x, вероятно, стоит того, что связано с несколькими уязвимостями и утечками, которые были устранены с 5.3.1

это случилось со мной несколько дней назад. Я сделал новую установку, и это все еще произошло. насколько каждый видит и основывается на ваших спецификациях сервера. скорее всего, это бесконечный цикл. это может быть не на самом PHP-коде, а на запросах, сделанных в Apache.

скажем, когда вы обращаетесь к этому URL- адресу http: // localhost / mysite / page_with_multiple_requests

Проверьте свой журнал доступа к Apache, если он получает несколько запросов. проследите этот запрос и проверьте код, который может вызвать «узкое место» для системы (my exec () при использовании sendmail). Узкое место, о котором он говорит, не обязательно должен быть «бесконечным циклом». Это может быть функция, которая требуется для завершения. или, возможно, некоторые из функций « выполнения программ» в php,

Возможно, вам потребуется также проверить запросы ajax (те, которые выполняются при загрузке страницы). если этот запрос ajax перенаправляется на тот же URL-адрес

например httpx: // localhost / mysite / page_with_multiple_requests

он будет «повторять» запросы сначала

это поможет, если вы разместите случайные строки или сам код, где заканчивается скрипт, возможно, там есть код цикла. imho php не просто вызовет случайные строки ни для чего.

http://blog.piratelufi.com/2012/08/browser-sending-multiple-requests-at-once/

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

Всегда помните: « Сбор мусора на PHP очень плохой », это не похоже на Java, любой другой такой язык. есть способ обеспечить сбор мусора через gc_collect_cycle , но, по моему личному мнению, это не решит вашу проблему. PHP освобождает всю память, используемую для выполнения страницы, как только цикл запроса-ответа завершен, поэтому вы можете столкнуться с проблемами памяти, если ваш скрипт работает долго, как фоновый скрипт (Gearman и т. Д.), Поскольку память не освобождается до скрипт запущен.

Если выше не так с вашим scr, pt, и, как вы сказали, нет кода, который требует такого огромного объема памяти, тогда проблема наиболее определенно в коде сама, а обновление до любой версии PHP не решит проблема. Однажды я столкнулся с одним из моих сценариев Gearman, и возникла проблема с одним из моих циклов, где я добавлял одну переменную в один из моих массивов, сама переменная была очень тяжелой (около 110 Кбайт данных). Поэтому я бы посоветовал сделать тщательный осмотр вашего кода.

изнасиловать

У меня была аналогичная проблема с PHP:

1) Проверьте свои журналы ошибок. Перед продолжением устраните КАЖДУЮ ошибку. 2) Рассмотрите возможность изменения конфигурации apache для устранения неиспользуемых модулей – это уменьшит площадь, необходимую PHP, – вот отличная ссылка для этого – она ​​специфична для WordPress, но все равно должна быть очень полезной http://thethemefoundry.com/blog/optimize- апач-WordPress /

Чтобы дать вам представление о том, какую ошибку я обнаружил, у меня был код, который пытался отправить контент в Facebook, Facebook затем изменил их API, так что это сломалось, я также использовал «expirator контента», который в основном означал, что он продолжал повторять размещать этот контент в Facebook и оставлять грузы, лежащие в памяти.

Из выходного файла профайлера я заметил пару вещей, которые мне не нравились / не доверяли много и смотрели на них:

Помимо того, что вы не знаете значения выходных чисел для обнаружения аномалии или того, как работают скрипты PHP …, разве это не проблема? Включить в тот же файл main.ph, который выглядит как рекурсивная вещь?

 2121 fl=D:\www\football\views\main.php 2122 fn=include::D:\www\football\views\main.php 

Заметил файл D:\www\football\views\main.php несколько раз использовал некоторые строковые функции, я думаю, он вызывает эти функции на данных, возвращаемых вашим запросом:

 strlen substr strtotime 

Если, как и на языке C, эти функции требуют, чтобы строки были завершены null или каким-либо другим концом терминатора строк, чтобы избежать проблем с памятью, я бы посмотрел на строки, возвращаемые вашим запросом.

Можете ли вы опубликовать URL-адрес своего веб-сайта?

Это известная ошибка в PHP v 5.2 для Windows, она присутствует по крайней мере до версии 5.2.3: https://bugs.php.net/bug.php?id=41615

Ни одно из предлагаемых исправлений не помогло нам, нам нужно будет обновить PHP.

Попробуйте запустить php через fcgid, это может помочь:

Это классические ошибки, которые вы увидите при запуске PHP в качестве модуля Apache. Мы много месяцев боролись с этими ошибками. Переключение на использование PHP через mod_fcgid (как рекомендует Джеймс) устранит все эти проблемы. Убедитесь, что у вас установлен последний распространяемый пакет Visual C ++:

http://support.microsoft.com/kb/2019667

Кроме того, я рекомендую перейти на 64-битную версию MySQL. Нет реальной причины запуска 32-битной версии.

Источник: Apache 2.4.6.0 из-за проблемы в php5ts.dll 5.5.1.0

Неустранимая ошибка: Недостаточно памяти (выделено SOLVED
У меня была схожая проблема, в течение нескольких месяцев нет решения. наконец, я проверял одну из папок apache, т. е. (\ apache \ conf \ extra), я наткнулся на этот файл, который управляет распределением памяти apache. имя файла httpd-mpm в этом файле, вы должны увеличить MaxMemFree, который установлен на 2048 на что-то выше, я взял мой до 10000 для первого MaxMemFree (IfModule! mpm_netware_module), а затем сделал второй MaxMemFree до 5000 IfModule mpm_netware_module.

Они решили мою проблему. Надеюсь, поможет

Я бы сказал, что на сервере заканчивается физическая / своп-память, поэтому PHP не может выделить достаточно памяти.

Можете ли вы вставить выходные данные здесь free ?

Для моего случая эта ошибка была вызвана из-за огромного запроса выбора (сотни тысяч возвращенных результатов).

Он возник сразу после добавления в мою базу данных миллионов записей, чтобы проверить масштабируемость WordPress, поэтому это была единственная вероятная причина для меня.