php работа с памятью

Как работает PHP-память

Я всегда слышал и искал новую php «хорошую практику написания», например: лучше (для производительности) проверить, существует ли ключ массива, чем поиск в массиве, но также кажется лучше для памяти:

предполагая, что у нас есть:

это выделяет 1040 байт памяти,

требуется 1136 байт

Я понимаю, что key и value конечно будет иметь различный механизм хранения, но пожалуйста, вы можете указать мне на принцип, как это работает?

Пример 2 (для @teuneboon):

потребляя ту же память:

4 ответов

Примечание, ответ ниже применим для PHP до к версии 7, как и в PHP 7, были внесены основные изменения, которые также включают структуры значений.

TL; DR

кроме того, важное примечание: графика здесь авторские права PHP internals book

хэш-карта для массивов PHP

массивы PHP и массивы C

PHP hash-ключи и коллизии карт

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

чтобы проиллюстрировать эти отношения в этих списках, вот график:

php работа с памятью. Смотреть фото php работа с памятью. Смотреть картинку php работа с памятью. Картинка про php работа с памятью. Фото php работа с памятью

еще один список: порядка

чтобы полностью поддерживать массивы, как они есть в PHP, также необходимо поддерживать ордер, так что это достигается с другим внутренним списком. Каждый элемент массивов также является членом этого списка. Это не будет иметь значения с точки зрения распределения памяти, так как в обоих вариантах этот список должен поддерживаться, но для полной картины я упоминаю этот список. Вот графика:

php работа с памятью. Смотреть фото php работа с памятью. Смотреть картинку php работа с памятью. Картинка про php работа с памятью. Фото php работа с памятью

элемент массива внутри

теперь мы готовы рассмотреть: что такое элемент массива, так, ведра:

хэш-таблица

об этом уже говорили элементы (ведра) и их структура, но есть и сама хэш-таблица, которая, по сути, является структурой данных массива. Итак, это называется _hashtable :

я не буду описывать все поля, так как я уже предоставил много информации, которая связана только с вопросом, но я кратко опишу эту структуру:

вывод

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

хотя оба массива доступны по-разному (т. е. через строку или целое значение), шаблон памяти в основном похож.

это потому, что распределение строк либо происходит как часть звал creation или когда новый ключ массива должен быть выделен; небольшая разница заключается в том, что числовые индексы не требуют всей структуры zval, потому что они хранятся как (без знака) долго.

наблюдаемые различия в распределении памяти настолько минимальны, что их можно в значительной степени объяснить либо неточностью memory_get_usage() или распределения из-за дополнительного создания ведра.

вывод

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

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

сборка мусора происходит.

когда вы говорите ему

int gc_collect_cycles ( void )

когда вы оставляете функцию

Если вы рассматриваете байт за байтом, как данные находятся в памяти. Различные порты будут влиять на эти значения. Производительность процессоров 64bit лучше всего, когда данные сидят на первом бит 64-битного слова. Для максимальной производительности конкретного двоичного файла они будут выделять начало блока памяти на первом бит, оставляя до 7 байтов неиспользуемыми. Этот конкретный процессор зависит от того, какой компилятор использовался для компиляции PHP.исполняемый. Я не могу предложить никакого способа предсказать точное использование памяти, учитывая, что она будет определяться по-разному разными компиляторами.

Alma Do, post переходит к специфике источника, который отправляется компилятору. Что запрашивает источник PHP и оптимизирует компилятор.

Источник

Управление памятью

Встроенный драйвер MySQL (mysqlnd) управляет памятью по-другому, в отличие от клиентской библиотеки MySQL (libmysql). Библиотеки различаются способом выделения и освобождения памяти, тем, как память выделяется по кускам во время чтения результатов из MySQL, существующими опциями для отладки и разработки, и тем, как результаты, считанные из MySQL, связаны с пользовательскими переменными PHP.

Следующая информация предназначена в качестве введения и обобщения для пользователей, заинтересованных в понимании mysqlnd на уровне C-кода.

Используемые функции для управления памятью

Любое ограничение памяти, установленное в PHP, также влияет на встроенный драйвер MySQL. Это может вызвать ошибки переполнения памяти при извлечении больших массивов данных, которые превышают размер оставшейся памяти, предоставленных РНР. Из-за того, что клиентская библиотека MySQL не использует функций управления памяти PHP, она не подчиняется ограничению памяти, установленному в PHP. При использовании libmysql, в зависимости от модели развёртывания, объем памяти, занимаемый PHP-процессом, может вырасти за пределы ограничений, установленных в PHP. В тоже время, PHP-скрипты могут обрабатывать больший объем массивов данных, так как области памяти, выделенные для хранения данных, не находятся под управлением РНР.

Функции системы управления памятью PHP вызываются встроенным драйвером MySQL через легковесную обёртку. Среди прочего, обёртка делает отладку легче.

Обработка массивов полученных данных

Различные MySQL-сервера и различные клиентские API различают буферизированные и небуферизированные результаты. Небуферизированные результаты передаются строка за строкой от MySQL к клиенту и клиент читает их по порядку. Буферизированные результаты забираются клиентской библиотекой целиком до передачи их клиенту.

Встроенный драйвер MySQL использует PHP-потоки для сетевого общения с сервером MySQL. Результаты, посланные MySQL-сервером, выбираются из сетевых буферов PHP-потоков в результирующий буфер mysqlnd. Результирующий буфер состоит из zvals. На втором шаге результаты становятся доступными PHP-скрипту. Последняя передача из результирующего буфера в PHP-переменные вызывает потребление памяти и в большинстве случаев оно заметно при использовании буферизированных результатов.

По умолчанию встроенный драйвер MySQL пытается избежать двойного хранения буферного результата в памяти. Результаты хранятся только один раз во внутренних результирующих буферах и их zvals. Когда результаты забираются в РНР-переменные PHP-скриптом, переменные будут ссылаться на внутренние результаты буферов. Результаты запросов к базам данных не копируются и хранятся в памяти только один раз. Достаточно пользователю изменить содержимое переменной, содержащей результаты работы базы данных, как будет выполнен механизм копирования при записи (Copy-On-Write), для того, чтобы избежать изменения ссылающего внутреннего буфера результата. Содержимое буфера не должно быть изменено, так как пользователь может принять решение прочитать результат во второй раз. Механизм копирования при записи реализуется с помощью дополнительного управления списком ссылок и использования стандартных zval счётчиков ссылок. Копирование при записи также должно быть сделано, если пользователь читает данные результата в PHP переменных и освобождает данные результата прежде, чем переменные будут уничтожены.

В общем, этот шаблон работает хорошо для скриптов, которые читают наборы данных единожды и не изменяют переменных, содержащих результаты. Его главный недостаток в накладных расходах памяти, вызванных дополнительным управлением ссылками, причина которого в первую очередь связана с тем, что пользовательские переменные, удерживающие результаты, не могут быть полностью освобождены до того, как система управления ссылками mysqlnd содержит ссылки на них. Встроенный драйвер MySQL удаляет ссылку на на пользовательские переменные когда массив полученных данных освобождается или выполняется механизм копирования при записи. Наблюдатель увидит рост общего потребления памяти пока массив полученных данных не освободится. Используйте статистику, чтобы проверить, скрипт явно произвёл освобождение данных результата или же драйвер сделал это неявно и поэтому память используется в течение более долгого времени, чем это необходимо. Статистика также помогает увидеть количество операций копирования при записи.

Режим копирования может быть включён принудительно, установив mysqlnd.fetch_data_copy=1.

Контроль и отладка

Журнал отладки может быть сконфигурирован для записи вызовов системы управления памятью. Это помогает увидеть когда память выделяется и освобождается. Однако, размер запрошенных кусков памяти может не быть в списке.

В некоторых последних версиях встроенного драйвера MySQL «mysqlnd» присутствует возможность эмуляции случайных ситуаций нехватки памяти. Эта возможность была задумана для использования только C-разработчиками библиотеки или авторами плагина mysqlnd. Пожалуйста, используйте поиск по исходному коду для соответствующей настройки PHP и для дальнейшей информации. Это возможность является недокументированной и может быть изменена в любое время без дополнительного уведомления.

Источник

Сколько памяти потребляют объекты в PHP и стоит ли использовать 64-битную версию?

php работа с памятью. Смотреть фото php работа с памятью. Смотреть картинку php работа с памятью. Картинка про php работа с памятью. Фото php работа с памятью

На этот пост меня вдохновило исследование потребления памяти для моего текущего большого проекта на ZendFramework. Как обычно, по результатам исследования, я был шокирован нашей программистской самонадеянностью, которая нередко присутствует, когда мы пишем что-либо большое на PHP. Да и, наверное, не только на PHP.

Но обо всём по порядку.

Как будем измерять

Для начала определимся, как мы будем измерять «вес». Вот шаблон:

Такой шаблон подходит для измерения новой выделяемой памяти, то есть памяти под переменные. А вот измерить, сколько едят определения, то есть описания функций и классов, таким подходом нельзя, так как они заносятся в память до начала выполнения скрипта. Для того чтобы измерить определения, воспользуемся следующим шаблоном:

Сколько весят «объекты»

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

Поговорим о тестах, связанных с ZendFramework. Загрузка определений классов Zend`а в память отжирает существенные ресурсы, тогда как ссылки на объекты уже потребляют не так много. Controller2 нужен, чтобы проверить, сколько будет отжирать аналогичный контроллер, если все промежуточные классы уже в памяти. Model2 создана для этих же целей.
В потенциале использование PHP акселератора сэкономит нам память на всех определениях, ибо они уже будут храниться в памяти. Давайте проверим это утверждение.

Тестирование акселераторов

Для тестирования был взят APC, и тесты запускались через web с помощью скрипта:

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

Как мы видим, акселератор хоть и экономит нам память для определений, но не полностью, поскольку PHP, видимо, переносит какие-то куски из кеша в текущую сессию.
Теперь перейдем от абстрактных тестов к вполне реальным.

Источник

memory_get_usage

(PHP 4 >= 4.3.2, PHP 5, PHP 7, PHP 8)

memory_get_usage — Возвращает количество памяти, выделенное для PHP

Описание

Возвращает количество памяти в байтах, которое было выделено PHP-скрипту на данный момент.

Список параметров

PHP не отслеживает память, которая выделялась не emalloc()

Возвращаемые значения

Возвращает количество памяти в байтах.

Примеры

Пример #1 Пример использования memory_get_usage()

// Это просто пример, цифры ниже будут
// отличаться в зависимости от вашей системы

Смотрите также

User Contributed Notes 15 notes

To get the memory usage in KB or MB

echo convert ( memory_get_usage ( true )); // 123 kb
?>

Note, that the official IEC-prefix for kilobyte, megabyte and so on are KiB, MiB, TiB and so on.

At first glance this may sound like «What the hell? Everybody knows, that we mean 1024 not 1000 and the difference is not too big, so what?». But in about 10 years, the size of harddisks (and files on them) reaches the petabyte-limit and then the difference between PB and PiB is magnificent.

Better to get used to it now. 🙂

To get the memory usage in KB or MB

function echo_memory_usage () <
$mem_usage = memory_get_usage ( true );

memory_get_usage() is used to retrieve the memory allocated to PHP only (or your running script). But intuitively, many people expect to get the memory usage of the system, based on the name of the function.

So if you need the overall memory usage, following function might be helpful. If retrieves the memory usage either in percent (without the percent sign) or in bytes by returning an array with free and overall memory of your system. Tested with Windows (7) and Linux (on an Raspberry Pi 2):

//
// Extract size (TODO: It seems that (at least) the two values for total and free memory have the unit «kB» always. Is this correct?
//

?>

The function getNiceFileSize() is not required. Just used to shorten size in bytes.

Источник

Как увеличить память и время для PHP скриптов

Настройки потребления ресурсов в PHP скриптах можно установить в главном конфигурационном файле php.ini, а также в самих скриптах.

В файле php.ini за это отвечают директивы из раздела Resource Limits (ограничение потребления ресурсов).

Как увеличить память для PHP скриптов

Для этого в файле php.ini найдите и отредактируйте директиву:

Эта директива задаёт максимальное время в секундах, в течение которого скрипт должен полностью загрузиться. Если этого не происходит, парсер завершает работу скрипта. Этот механизм помогает предотвратить зависание сервера из-за плохо написанного скрипта. По умолчанию на загрузку даётся 30 секунд. Если PHP запущен из командной строки, это значение по умолчанию равно 0.

На максимальное время выполнения не влияют системные вызовы, потоковые операции и т.п.

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

Веб-серверы обычно имеют свои настройки тайм-аута, по истечении которого сами завершают выполнение скрипта PHP. В Apache есть директива Timeout, в IIS есть функция CGI timeout. В обоих случаях по умолчанию установлено 300 секунд. Точные значения можно узнать из документации к веб-серверу.

Функция для увеличения и ограничения времени выполнения PHP

Функция set_time_limit ограничивает время выполнения скрипта.

Она задает время в секундах, в течение которого скрипт должен завершить работу. Если скрипт не успевает, вызывается фатальная ошибка. По умолчанию дается 30 секунд, либо время, записанное в настройке max_execution_time в php.ini (если такая настройка установлена).

При вызове set_time_limit() перезапускает счетчик с нуля. Другими словами, если тайм-аут изначально был 30 секунд, и через 25 секунд после запуска скрипта будет вызвана функция set_time_limit(20), то скрипт будет работать максимум 45 секунд.

Возвращаемые значения: возвращает TRUE в случае успеха, иначе FALSE.

Внимание: эта функция не работает, если PHP работает в безопасном режиме. Обойти это ограничение можно только выключив безопасный режим или изменив значение настройки в php.ini.

Замечание: функция set_time_limit() и директива max_execution_time влияют на время выполнения только самого скрипта. Время, затраченное на различные действия вне скрипта, такие как системные вызовы функции system(), потоковые операции, запросы к базам данных и т.п. не включаются в расчет времени выполнения скрипта. Это не относится к системам Windows, где расчитывается абсолютное время выполнения.

Обе set_time_limit(…) и ini_set(‘max_execution_time’,…); не учитывают время, потраченное функциями sleep, file_get_contents, shell_exec, mysql_query и некоторыми другими.

Увеличение выделенной памяти для PHP скриптов

Директива в файле php.ini

задаёт максимальный объем памяти в байтах, который разрешается использовать скрипту. Это помогает предотвратить ситуацию, при которой плохо написанный скрипт съедает всю доступную память сервера. Для того, чтобы убрать ограничения, установите значение этой директивы в -1.

В версиях до PHP 5.2.1 для использования этой директивы, она должна была быть указана на этапе компиляции. Так, ваша строка конфигурации должна была включать: —enable-memory-limit. Эта опция компиляции была также необходима для использования функций memory_get_usage() и memory_get_peak_usage() до версии 5.2.1.

Если используется целое число, то значение измеряется байтами. Вы также можете использовать сокращённую запись.

Доступные опции: K (для килобайт), M (для мегабайт) и G (для гигабайт; доступна начиная с PHP 5.1.0); они регистронезависимы. Все остальное считается байтами. 1M равно одному мегабайту или 1048576 байтам. 1K равно одному килобайту или 1024 байтам. Эти сокращения вы можете использовать в php.ini и в функции ini_set(). Обратите внимание, что числовое значение приводится к типу integer; например, 0.5M интерпретируется как 0.

Увеличение времени парсинга данных из запроса.

Директива в файле php.ini

задаёт максимальное время в секундах, в течение которого скрипт должен разобрать все входные данные, переданные запросами вроде POST или GET. Это время измеряется от момента, когда PHP вызван на сервере до момента, когда скрипт начинает выполняться. Значение по умолчанию -1, что означает, что будет использоваться max_execution_time. Если установить равным 0, то ограничений по времени не будет.

При запуске в командной строке значение директивы установлено на -1 (неограниченно).

Увеличение глубины вложенности входных переменных

Директива в файле php.ini

Ограничение на количество входных переменных

Директива в файле php.ini

Внимание: после внесения изменений в файл php.ini необходимо перезагрузить веб-сервер, чтобы изменения вступили в силу.

Проверка использование ресурсов

Функция getrusage получает информацию об использовании текущего ресурса.

Возвращаемые значения: возвращает ассоциативный массив, содержащий данные возвращённые из системного вызова. Имена элементов соответствуют документированным именам полей.

Пример использования getrusage():

php работа с памятью. Смотреть фото php работа с памятью. Смотреть картинку php работа с памятью. Картинка про php работа с памятью. Фото php работа с памятью

Увеличение разрешённого размера файлов для загрузки на сервер

Кроме описанных ограничений на потребление непосредственных ресурсов веб-сервера, также имеются ограничения, которые оказывают косвенное воздействие на ресурсы: например, загрузка слишком большого файла на сервер может потребовать большого количества ресурсов для его обработки, либо привести к переполнению дискового хранилища сервера. Поэтому существуют дополнительные лимиты, включённые в другие разделы конфигурационного файла помимо Resource Limits.

В частности, директива

устанавливает максимальный размер закачиваемого файла.

Если используется целое число, значение измеряется байтами. Вы также можете использовать сокращённую запись, которая описана чуть выше.

Максимально допустимый размер данных, отправляемых методом POST

Методом пост могут отправляться как текстовые данные (например, при отправке комментария на сайт), так и файлы. Если вы увеличили значение upload_max_filesize чтобы иметь возможность загружать файлы большего размера на сайт, то также нужно увеличить и значение директивы:

которая устанавливает максимально допустимый размер данных, отправляемых методом POST. Это значение также влияет на загрузку файлов. Для загрузки больших файлов это значение должно быть больше значения директивы upload_max_filesize. В сущности, memory_limit должна быть больше чем post_max_size. Если используется integer, значение измеряется байтами. Вы также можете использовать сокращённую запись, которая описана выше. Если размер POST-данных больше чем post_max_size, суперглобальные переменные $_POST и $_FILES будут пустыми. Это можно отследить различными способами, например передав $_GET переменную в скрипт, обрабатывающий данные, т.е.

Источник

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *