Использование памяти в 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

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