Как правильно посмотреть сколько нужно памяти для выполнения php скрипта?
PHP Fatal error: Out of memory (allocated 482349056) (tried to allocate 20480 bytes) in /YmlParser.php on line 155 PHP Fatal Error ‘yii\base\ErrorException’ with message ‘Out of memory (allocated 482349056) (tried to allocate 20480 bytes)’
Запускаю этот скрипт на локалке с функцией memory_get_usage
После выполнения скрипта возвращает
На сервере должно хватать, так как там гиг.
Надеюсь, понятно объяснил, благодарю за помощь.
Отслеживать
задан 20 апр 2018 в 10:30
301 1 1 золотой знак 5 5 серебряных знаков 17 17 бронзовых знаков
482349056 чем вам не объем использованной под задачу памяти? а сколько нужно будет в действительности, никто не скажет, пока скрипт не выполнится
20 апр 2018 в 10:37
@teran оке, это значит 0.4 гигабайта ОЗУ, на сервере Гиг, но все равно вибвает такую ошибку, не могли бы подсказать, почему?
20 апр 2018 в 10:44
начните с проверки memory_limit в php.ini
20 апр 2018 в 11:13
@teran забыл сказать, поставил -1 у memory_limit 😀 Сейчас проверил через команду FREE на сервере, вывело total(1040330752), free(491642880). Как я понимаю слишком мало свободной памяти для выполнения этого скрипта?
20 апр 2018 в 11:24
1 ответ 1
Сортировка: Сброс на вариант по умолчанию
На сервере может и 1ГБ, но со всеми активными процессами будет всегда меньше чем указано.
Никакие проверки memory_limit в php.ini не помогут. Вы получаете ошибку PHP Fatal error: Out of memory, а не более общую Fatal error: Allowed memory size of . , что означает что система просто не может выделить больше памяти, чем у нее доступно.
Для выполнения данного скрипта просто недостаточно памяти, вам нужно увеличить обьем доступной памяти или поменять библиотеку, которая более экономично бы использовала оперативную память, если это конечно возможно в рамках реализуемой вами задачи.
Сколько памяти потребляют объекты в PHP и стоит ли использовать 64-битную версию?
На этот пост меня вдохновило исследование потребления памяти для моего текущего большого проекта на ZendFramework. Как обычно, по результатам исследования, я был шокирован нашей программистской самонадеянностью, которая нередко присутствует, когда мы пишем что-либо большое на PHP. Да и, наверное, не только на PHP.
Но обо всём по порядку.
- Работа с памятью (и всё же она есть)
- Насколько большие массивы (и значения) в PHP? (Подсказка: ОЧЕНЬ БОЛЬШИЕ)
Как будем измерять
Для начала определимся, как мы будем измерять «вес». Вот шаблон:
$startMemory = 0; $startMemory = memory_get_usage(); // Измеряемое echo (memory_get_usage() - $startMemory) . ' bytes' . PHP_EOL;
Такой шаблон подходит для измерения новой выделяемой памяти, то есть памяти под переменные. А вот измерить, сколько едят определения, то есть описания функций и классов, таким подходом нельзя, так как они заносятся в память до начала выполнения скрипта. Для того чтобы измерить определения, воспользуемся следующим шаблоном:
$startMemory = 0; $startMemory = memory_get_usage(); // Измеряемое include $testfile; echo (memory_get_usage() - $startMemory - $include_overhead) . ' bytes' . PHP_EOL;
- Длины абсолютного пути до файла
- Каким по счёту этот файл был включён (каждые 8, 16, 32, 64 и т.д. идёт дополнительное выделение под внутренние структуры)
- Заполненностью внутренних структур самого PHP, которые периодически довыделяют себе памяти на будущее.
Сколько весят «объекты»
Итак был написан TestSuite для автоматического запуска большого количества тестов. Все тесты запускались в VirtualBox для Ubuntu 12.04.1 LTS i386 и Ubuntu 12.04.1 LTS amd64. Версия PHP — 5.3.10, ZendFramework — 1.11.11. Команда для запуска в консоли:
php run.testsuite-without-accelerator.php
Дополнительно я сделал тест на своей машине с Gentoo amd64 для контроля. PHP-акселераторы при запуске из консоли не работают. Вот результаты:
| a.mention_variable | Упоминание переменной | 44 | 80 | 48 |
| a.new_null_variable | Создание новой переменной со значением null | 108 | 208 | 144 |
| a.unset_null_variable | Удаление переменной | -108 | -208 | -144 |
| stdClass.new | Создание объекта | 120 | 232 | 168 |
| stdClass.tovar1 | Создание объекта и ссылки $a на него | 264 | 512 | 352 |
| stdClass.tovar2_unset_and_thesame | Удаление ссылки $a и пересоздание ссылки $a | 0 | 0 | 0 |
| stdClass.tovar3_unset_and_another | Удаление ссылки $a и создание ссылки $b | 0 | 0 | 0 |
| stdClass.tovar4_another | Создание объекта и ссылки $c на него | 264 | 512 | 352 |
| stdClass.tovar5_addlink | Создание ссылки $a на тот же объект что и $b | 64 | 128 | 96 |
| stdClass.z.free_memory | Удаление ссылок $a, $b и $c | -592 | -1152 | -800 |
| myclass.a.empty | Описание класса A | 700 | 1344 | 1128 |
| myclass.aa.interface | Описание интерфейса A | 700 | 1344 | 1128 |
| myclass.ab.final | Описание финального класса AB | 700 | 1344 | 1128 |
| myclass.ac.abstract | Описание абстрактного класса AC | 700 | 1344 | 1128 |
| myclass.b.extended.empty | Описание класса B, расширяющего A | 700 | 1344 | 1128 |
| myclass.c.empty.namespace | Описание пустого неймспейса C | 0 | 0 | 0 |
| myclass.d.construct | Описание класса D с конструктором | 1104 | 2288 | 1920 |
| myclass.dd.method | Описание класса DD с методом | 1088 | 2280 | 1912 |
| myclass.ddd.private.var | Описание класса DDD с приватной переменной | 960 | 1840 | 1472 |
| myclass.dddd.public.var | Описание класса DDDD с публичной переменной | 960 | 1840 | 1472 |
| myclass.ddddd.static.var | Описание класса DDDDD со статической переменной | 960 | 1840 | 1472 |
| myclass.e.extended.destruct | Описание класса E с деструктором, расширяющим класс D | 1344 | 2704 | 2272 |
| myclass.e.instance.ab | Создание объекта AB и ссылки $e на него | 264 | 512 | 352 |
| myclass.e.instance.ddddd | Создание объекта DDDDD и ссылки $e на него | 0 | 0 | 0 |
| myclass.e.instance.e | Создание объекта E и ссылки $e на него | 0 | 0 | 0 |
| myclass.f.instance.ddddd | Создание объекта DDDDD и ссылки $f на него | 264 | 512 | 352 |
| myclass.z.free_memory | Удаление ссылок $e, $f | -484 | -944 | -656 |
| zend.a.init.autoload | Инициализация autoload для ZendFramework | 127 444 | 276 288 | 249 232 |
| zend.a.init.model | Инициализация адаптера по умолчанию для базы | 1 018 388 | 2 081 600 | 1 871 256 |
| zend.extended.controller1 | Определение контроллера от Zend_Controller_Action. Попутно происходит подгрузка стандартных зендовских классов | 378 296 | 809 384 | 712 816 |
| zend.extended.controller2 | Определение контроллера. Класы Zend уже подгружены, смотрим, сколько весит наш класс | 11 328 | 19 608 | 16 008 |
| zend.extended.model1 | Определение модели от Zend_Db_Table. Попутно происходит подгрузка стандартных зендовских классов. | 27 936 | 48 544 | 40 224 |
| zend.extended.model2 | Определение модели. Класы Zend уже подгружены, смотрим, сколько весит наш класс | 27 936 | 48 536 | 40 208 |
| zend.use.model1.e.instance1 | Создание объекта Model1 и ссылки $e на него | 2492 | 4648 | 3432 |
| zend.use.model1.f.instance2 | Создание объекта Model1 и ссылки $f на него | 1764 | 3256 | 2488 |
| zend.use.model1.g.instance3 | Создание объекта Model1 и ссылки $g на него | 1764 | 3256 | 2488 |
| zend.use.model2.e.instance1 | Создание объекта Model2 и ссылки $e на него | 740 | 1400 | 944 |
| zend.use.model2.f.instance2 | Создание объекта Model2 и ссылки $f на него | 0 | 0 | 0 |

Можно заметить, что сборка Gentoo потребляет на 10-20% меньше памяти, а в редких случаях экономия доходит до 50%. Видимо, размер внутренних структур зависит от оптимизаций для процессора. Для экперимента я пересобирал php с разными вариантами CFLAGS, но он от этого не стал потреблять больше. Видимо разница проявляется не из-за пересборки самого PHP, а из пересборки стандартных Сишных библиотек.

Как было отмечено выше, точно измерить $include_overhead сложно, поэтому если вы запустите данные тесты, то у вас могут получится так, что потребление памяти будет прыгать на 4, 8, 12, 16 байт, даже в тестах, которые должны потреблять одинаково. Не стоит акцентировать на этом внимания. Я запускал тесты в разном порядке и более-менее установил истинное потребление памяти.
Поговорим о тестах, связанных с ZendFramework. Загрузка определений классов Zend`а в память отжирает существенные ресурсы, тогда как ссылки на объекты уже потребляют не так много. Controller2 нужен, чтобы проверить, сколько будет отжирать аналогичный контроллер, если все промежуточные классы уже в памяти. Model2 создана для этих же целей.
В потенциале использование PHP акселератора сэкономит нам память на всех определениях, ибо они уже будут храниться в памяти. Давайте проверим это утверждение.
Тестирование акселераторов
Для тестирования был взят APC, и тесты запускались через web с помощью скрипта:
php run.testsuite-with-accelerator.php
Результаты приведены только тестов, где акселератор оказывает влияние:
| myclass.a.empty | Описание класса A | 840 | 672 | 1480 | 1256 |
| myclass.aa.interface | Описание интерфейса A | 856 | 676 | 1512 | 1264 |
| myclass.ab.final | Описание финального класса AB | 844 | 672 | 1488 | 1256 |
| myclass.ac.abstract | Описание абстрактного класса AC | 852 | 680 | 1504 | 1264 |
| myclass.b.extended.empty | Описание класса B, расширяющего A | 912 | 700 | 1512 | 1264 |
| myclass.c.empty.namespace | Описание пустого неймспейса C | 176 | -16 | 184 | -72 |
| myclass.d.construct | Описание класса D с конструктором | 1256 | 960 | 2448 | 1736 |
| myclass.dd.method | Описание класса DD с методом | 1268 | 968 | 2432 | 1728 |
| myclass.ddd.private.var | Описание класса DDD с приватной переменной | 1140 | 964 | 2000 | 1760 |
| myclass.dddd.public.var | Описание класса DDDD с публичной переменной | 1132 | 952 | 2000 | 1760 |
| myclass.ddddd.static.var | Описание класса DDDDD со статической переменной | 1124 | 952 | 2000 | 1760 |
| myclass.e.extended.destruct | Описание класса E с деструктором, расширяющим класс D | 1528 | 1228 | 2888 | 2160 |
| myclass.z.free_memory | Удаление ссылок $e, $f | -332 | -548 | -784 | -1024 |
| zend.a.init.autoload | Инициализация autoload для ZendFramework | 127 596 | 16 196 | 276 440 | 28 992 |
| zend.a.init.model | Инициализация адаптера по умолчанию для базы | 1 018 564 | 251 840 | 2 081 696 | 479 280 |
| zend.extended.controller1 | Определение контроллера от Zend_Controller_Action. Попутно происходит подгрузка стандартных зендовских классов | 378 464 | 66 804 | 809 608 | 120 864 |
| zend.extended.controller2 | Определение контроллера. Класы Zend уже подгружены, смотрим сколько весит наш класс | 11 476 | 11 140 | 19 792 | 19 056 |
| zend.extended.model1 | Определение модели от Zend_Db_Table. Попутно происходит подгрузка стандартных зендовских классов. | 28 080 | 25 676 | 48 704 | 42 944 |
| zend.extended.model2 | Определение модели. Класы Zend уже подгружены, смотрим, сколько весит наш класс | 28 080 | 25 704 | 48 672 | 42 960 |

Я также производил некоторые тесты с xcache и заметил 2 отличия от APC. Во-первых: xcache проигрывает (почти всегда) на 10-15% по экономии памяти. А во-вторых: xcache сразу отдаёт файлы из кеша, тогда как APC — только после повторного обращения. Хоть и бесполезное, но преимущество.

Сразу отмечу, в результатах разброс гораздо больше, чем при тестировании без акселератора, поскольку файлы не переименовывались и $include_overhead рассчитывался с большой ошибкой.
Как мы видим, акселератор хоть и экономит нам память для определений, но не полностью, поскольку PHP, видимо, переносит какие-то куски из кеша в текущую сессию.
Теперь перейдем от абстрактных тестов к вполне реальным.
Тестирование небольшого приложения на ZendFramework
Для тестирования было взято тестовое задание одного из наших программистов (Simple-blog): сервис коллективного блога с функциями: регистрации, авторизации, чтения списка постов, открытия поста и его комментирования. В конце index.php было написано:
echo memory_get_peak_usage();
чтобы проверить, какое максимальное количество памяти пожирал скрипт во время генерации страницы. Результаты:
| Список постов | 5 328 648 | 1 792 968 | 10 938 160 | 3 306 720 |
| Пост и его коментарии | 5 372 356 | 1 831 452 | 11 015 320 | 3 373 528 |
| Логин форма | 6 781 656 | 2 277 164 | 13 982 104 | 4 187 600 |
| Форма регистрации | 6 796 496 | 2 291 568 | 14 009 384 | 4 211 432 |
Дополнительно проверялась сборка под Gentoo, он оказался на 25% эффективнее во всех тестах.
Выводы
- Если память дорогой ресурс (например VPS) и не особо нужны 64-битные числа, то есть смысл использовать 32-битную версию ОС. Выигрыш будет ~ в 1.8 раза.
- В ОС, в которых происходит заточка пакетов под текущую архитектуру можно дополнительно сэкономить 25% памяти.
- Ничто так не потребляет память в PHP, как тяжёлый фреймворк. Использование акселератора не спасает от поедания памяти тяжёлыми фреймворками. Возможно имеет смысл ознакомиться со следующим сравнением PHP фреймворков, чтобы выбрать для себя баланс популярности/производительности.
- Ситуацию, которая изображена на картинке для привлечения внимания, можно получить, если размер APC кеша окажется исчерпан. Этого добиться не сложно, если у вас много сайтов на одной машине, а вы установили APC, не проверяя хватит ли вам памяти. При этом статистика (apc.php) вам будет сообщать, что у вас есть ещё около 40% памяти, но ей особо не следует верить, ибо у APC плохой менеджер памяти и он просто не умеет использовать её эффективно. Лучше всегда обращайте внимание на hits и miss значения.
Кодяра
UPD
AntonShevchuk добавил результаты для тестов на PHP 5.4. PHP 5.4 выглядит гораздо экономичнее по сравнению с 5.3. Официальная документация это также подтверждает.
Форум
Как увеличить объем памяти на исполнение скрипта(memory_limit не помогает!)
Обсуждение общих вопросов
Первое новое сообщение • 5 сообщений • Страница 1 из 1
bogdan_titomir Сообщения: 3 Зарегистрирован: 04 ноя 2017, 21:07
Как увеличить объем памяти на исполнение скрипта(memory_limit не помогает!)
Нужно выделить парсеру примерно 1,5 гигов оперативной памяти но выделяет макс 939мб. Memory_limit не помогает, камрады выручайте что делать? Заранее спасибо!
max80dnepr Сообщения: 22 Зарегистрирован: 18 авг 2013, 16:59
Re: Как увеличить объем памяти на исполнение скрипта(memory_limit не помогает!)
Да,меня тоже это интересует.
bogdan_titomir Сообщения: 3 Зарегистрирован: 04 ноя 2017, 21:07
Re: Как увеличить объем памяти на исполнение скрипта(memory_limit не помогает!)
max80dnepr писал(а): Да,меня тоже это интересует.
Ждем комментарий Максима, думаю он знает.
Максим Сообщения: 6022 Зарегистрирован: 11 дек 2010, 20:29
Re: Как увеличить объем памяти на исполнение скрипта(memory_limit не помогает!)
32-битный модуль PHP имеет максимальный лимит ~1.5 ГБ, а с учётом расширений PHP (intl, memcache,mongo, ioncube и т.д.) которые есть в Open Server и их настроек скрипту реально достаётся от 0.8 до 1.3 гигабайта максимум. Так что ничего удивительного. Хотите больше памяти — используйте 64-битный модуль PHP.
bogdan_titomir Сообщения: 3 Зарегистрирован: 04 ноя 2017, 21:07
Re: Как увеличить объем памяти на исполнение скрипта(memory_limit не помогает!)
Максим писал(а): 32-битный модуль PHP имеет максимальный лимит ~1.5 ГБ, а с учётом расширений PHP (intl, memcache,mongo, ioncube и т.д.) которые есть в Open Server и их настроек скрипту реально достаётся от 0.8 до 1.3 гигабайта максимум. Так что ничего удивительного. Хотите больше памяти — используйте 64-битный модуль PHP.
Спасибо за быстрый ответ, легче наверно basic версию скачать там как раз нет mongo и тд чем удалять их из ultimate версии.
Ошибка Allowed memory size
Переводится, как «неустранимая ошибка: допустимый размер памяти. ». Данная ошибка говорит о том, что скрипт превысил допустимый размер выделяемый ему оперативной памяти.

Fatal error: Allowed memory size of 408933426 bytes exhausted (tried to allocate 3009682 bytes)
Данная ошибка показывает:
- 408933426 bytes — допустимый размер памяти
- 3009682 bytes — сколько не хватает памяти.
Ошибка исчерпания лимита памяти возникает, когда сайт потребляет больше оперативной памяти, чем ему доступно (указано в php.ini).
Как исправить ошибку «Fatal error: Allowed memory size. »?
Наш хостинг предоставляет возможность пользователю менять настройки PHP. Для устранения данной ошибки, нам нужно будет увеличить параметр memory_limit для версии PHP, на которой работает Ваш сайт. Узнать версию Вашего сайта Вы можете в панели хостинга в разделе «WWW» — пункт «WWW-домены».

После того, как мы узнали версию PHP, нам нужно перейти в раздел «WWW» — пункт «PHP», выбираем нужную нам версию и нажимаем кнопку «Настройка».

В открывшемся окне будут представлены параметры PHP, нас интересует memory_limit. Сейчас напротив поля memory_limit будет указано доступное количество оперативной памяти. Чтобы изменить этот параметр, нам нужно нажать на него и сверху выбрать кнопку «Изменить» или кликнуть на него 2 раза и ввести нужное нам количество оперативной памяти.

Будьте осторожны на каждом тарифе хостинга есть свое ограничение по лимиту оперативной памяти.
Также узнать версию PHP и объём доступной памяти можно с помощью функции phpinfo(). Для этого нужно создать php-скрипт, например с именем: t.php. После создания, нужно будет добавить в него следующий код:
После добавления кода, нужно загрузить файл в директорию сайта. И при открытии сайта, дописать к адресу /t.php (Например, ваш_сайт.ru/t.php). После чего откроется страница, где будут указаны все параметры PHP.
