Использование памяти в php-процессе
СУЩНОСТЬ
Краткие рекомендации (из более подробной информации, см. ответы)
Чтобы избежать утечек памяти, вы можете:
- отменять переменные сразу, когда они становятся бесполезными
- вы можете использовать xdebug для подробного отчета о потреблении памяти по функциям и поиска утечек памяти
- вы можете установить memory_limit (например, до 5 МБ), чтобы избежать размещения фиктивной памяти
Вопрос
Для чего php может использовать память, кроме библиотек и переменных?
Я контролирую память, используемую переменными и ее ~ 3Mb с помощью этого кода:
$vars = array_keys(get_defined_vars());
$cnt_vars = count($vars);
$allsize = 0;
for ($j = 0; $j < $cnt_vars; $j++) {
try
{
$size = @serialize($$vars[$j]);
$size = strlen($size);
}
catch(Exception $e){
$str = json_encode($$vars[$j]);
$str = str_replace(array('{"','"}','":"','":'), '', $str);
$size = strlen($str);
}
$vars[$j] = array(
'size' => $size,
'name' => $vars[$j]
);
$allsize += $size;
}
и библиотеки берут ~ 18Mb (libcurl и т.д.)
Так что сумма его 21 Мб, но
pmap -x (процесс) показывает, что общее потребление памяти составляет kB: 314028 RSS: 74704 Dirty: 59672
так, общее реальное потребление ~ 74Mb.
Также я вижу некоторые большие блоки с [anon] отображением в моем pmap
Для чего PHP использует эти блоки?
версия php: 5.5.9-1ubuntu4.14
Расширения php:
[email protected]:~# php -m
[PHP Modules]
bcmath
bz2
calendar
Core
ctype
curl
date
dba
dom
ereg
exif
fileinfo
filter
ftp
gd
gettext
hash
iconv
json
libxml
mbstring
mcrypt
mhash
openssl
pcntl
pcre
PDO
pdo_pgsql
pgsql
Phar
posix
readline
Reflection
session
shmop
SimpleXML
soap
sockets
SPL
standard
sysvmsg
sysvsem
sysvshm
tokenizer
wddx
xml
xmlreader
xmlwriter
Zend OPcache
zip
zlib
[Zend Modules]
Zend OPcache
Ответы
Ответ 1
ПРИМЕЧАНИЕ: это не совсем ответ, а информация, запрошенная OP, но поле комментариев слишком мало для этого... Это больше инструментов для отладки таких проблем.
Документы Xdebugs довольно обширны, они должны сказать, как использовать это намного лучше, чем я мог, копируя свои документы сюда. script, который вы дали, немного нечеткое, поэтому я сам не выполнял трассировку, но это даст вам линейные различия в использовании памяти.
В основном установленный xdebug.show_mem_delta
- 1
с включенным Xdebug для генерации трассировки функции, который затем можно открыть в текстовом редакторе, чтобы увидеть, какая именно часть - это то, что утечки памяти.
Затем вы можете сравнить исходную (или среднюю) общую память, чтобы увидеть, насколько она отличается от реального использования памяти, которое вы видите.
TRACE START [2007-05-06 14:37:26]
0.0003 114112 +114112 -> {main}() ../trace.php:0
Здесь общая память будет 114112
.
Если разница действительно велика, вы можете использовать что-то вроде shell_exec()
, чтобы получить реальное использование памяти между всеми строками, и вывести это, а затем вы можете сравнить этот вывод с выходом памяти Xdebugs, чтобы увидеть, где происходит различие.
Если разница от самой первой строки script, виновником может быть расширение PHP. См. php -m
, если есть какие-либо подозрительные расширения.
Ответ 2
PHP не такой, как код C или CPP, который компилируется в одиночный двоичный файл. Все ваши скрипты выполняются внутри Zend Virtual Machine. И большая часть памяти потребляется самой виртуальной машиной. Это включает в себя память, используемую загруженными расширениями разделяемые библиотеки (.so файлы), используемые процессом PHP и любыми другими совместно используемыми ресурсами.
Я не помню точный источник, но где-то я читал, что почти 70% всех циклов процессора потребляются внутри PHP, и только 30% попадают в ваш код (пожалуйста, поправьте меня, если я ошибаюсь здесь). Это напрямую не связано с потреблением памяти, но должно дать представление о том, как работает PHP.
Об анонных блоках я нашел некоторые подробности в другом ответе SO. Ответ о Java, но то же самое относится и к PHP.
Блоки анонов - это "большие" блоки, выделенные через malloc или mmap - см.. страница руководство Таким образом, они не имеют ничего общего с кучей Java (другие чем тот факт, что вся куча должна храниться в такой блок).
Я бы рекомендовал отключить некоторые расширения. Это должно сэкономить вам неиспользованную память.
Ответ 3
Прежде всего сделайте массив, чтобы исследовать память, которую он принимает
$startMemory = memory_get_usage();
$array = range(1, 100000);
echo memory_get_usage() - $startMemory, ' bytes';
одно целое число 8 bytes
(на a 64 bit unix machine
и с использованием типа long
), а здесь 100000 integers
, поэтому вам, очевидно, понадобится 800000 bytes
. Это что-то вроде 0.76 MB
.
Этот массив дает 14649024 bytes
. Thats 13.97 MB
- в 18 раз больше, чем оценено.
Ниже приведен краткий обзор использования памяти для различных компонентов:
| 64 bit | 32 bit
---------------------------------------------------
zval | 24 bytes | 16 bytes
+ cyclic GC info | 8 bytes | 4 bytes
+ allocation header | 16 bytes | 8 bytes
===================================================
zval (value) total | 48 bytes | 28 bytes
===================================================
bucket | 72 bytes | 36 bytes
+ allocation header | 16 bytes | 8 bytes
+ pointer | 8 bytes | 4 bytes
===================================================
bucket (array element) total | 96 bytes | 48 bytes
===================================================
total total | 144 bytes | 76 bytes
Опять же, для больших статических массивов, если я называю:
$startMemory = memory_get_usage();
$array = new SplFixedArray(100000);
for ($i = 0; $i < 100000; ++$i) {
$array[$i] = $i;
}
echo memory_get_usage() - $startMemory, ' bytes';
В результате получится 5600640 bytes
Thats 56 bytes
за элемент и, следовательно, намного меньше, чем 144 bytes
на элемент, используемый обычным массивом. Это связано с тем, что фиксированный массив не нуждается в структуре ковша. Поэтому для каждого элемента требуется только один zval (48 bytes)
и один pointer (8 bytes)
, дающий наблюдаемый 56 bytes
.
Надеюсь, это будет полезно.
Ответ 4
Нет ничего плохого в цифрах, которые вы видите, вы не должны их комбинировать, это просто "утроится", вы видите разные разделы (только для чтения, исполняемые, записываемые) для библиотек, перечисленных отдельно, ваш номер правильный.