Подтвердить что ты не робот

Мне больше нравится потребление памяти в Php 7 по сравнению с PHP 5.6

Когда я делал бенчмарк, я обнаружил, что PHP 7 использует больше памяти, чем PHP 5.6.

Итак, я сделал тест. Я запустил script, содержащий только:

  $a=10;

и ниже приведены результаты для памяти, используемой при использовании PHP CLI без каких-либо модулей (php -n)

php 5.6 = 222600 Bytes
php 7.0 = 350448 Bytes

* PHP 5.6.23 (cli) (built: Jun 22 2016 12:13:15)
Copyright (c) 1997-2016 The PHP Group
Zend Engine v2.6.0, Copyright (c) 1998-2016 Zend Technologies 

* PHP 7.0.9 (cli) (built: Jul 20 2016 10:47:41) ( NTS )
Copyright (c) 1997-2016 The PHP Group
Zend Engine v3.0.0, Copyright (c) 1998-2016 Zend Technologies

Среда

  • ОС: окно 10
  • Сервер: IIS (хотя я использовал CLI, а не сервер), с быстрым cgi
  • машина: 64 бит
  • PHP-5.6.23-NTS-Win32-VC11-64
  • PHP-7.0.9-NTS-Win32-VC14-64

Может кто-нибудь объяснить, почему я получил этот результат?


Дополнительные тесты

Используя этот код, как предлагается @gordon,

$i=0;
while ($i++ < 100000) ;

php 5.6: 227408 байт

php 7.0: 386640 байт

Я определил использование памяти с помощью этого кода:

echo PHP_EOL;
echo "Memory Usage :".memory_get_usage();
echo PHP_EOL;
echo "Real Memory Usage :".memory_get_usage(true);
echo PHP_EOL;
echo "Real Peak Memory Usage :".memory_get_peak_usage(true);
echo PHP_EOL;
echo "Peak Memory Usage :".memory_get_peak_usage();
4b9b3361

Ответ 1

Чтобы понять ответ на свой вопрос - вам нужно понять, как выделяет память PHP5 и PHP7.

PHP5 выделение памяти "по запросу", предполагая им структуру Zend Engine.

В PHP7 это некоторые оптимизации, сделанные с этой стороны, поэтому память выделяет "кусками"

  • При запуске он выделяет большую часть памяти
  • В распределении приложений он выделяет небольшой фрагмент, чтобы избежать фрагментации

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

И да, PHP7 очень экономит память на больших программах.

Вы можете просмотреть все эти различия на рисунках ниже:

Распределение памяти PHP для больших программ Распределение памяти PHP для небольших программ

Графика, построенная с помощью эталона: 1.php

<?php

ini_set('memory_limit', '5G');
$a=range(1,$argv[1]);

echo PHP_EOL;
echo "Memory Usage :".memory_get_usage();
echo PHP_EOL;
echo "Real Memory Usage :".memory_get_usage(true);
echo PHP_EOL;
echo "Real Peak Memory Usage :".memory_get_peak_usage(true);
echo PHP_EOL;
echo "Peak Memory Usage :".memory_get_peak_usage();
echo PHP_EOL;

bench.sh

// Small programs
(for i in $(seq 0 5 5000);do php5 dev/Tools/mem/1.php $i|cut -f 2 -d:|sed -r 's/^$/;/g'|sed -r 's/([0-9]+)$/\1,/g'|tr -d '\n'; echo $i; done)|tr -d '\n'|sed -r 's/$/]/g'|sed -r 's/^;/[/g'>php5.m
(for i in $(seq 0 5 5000);do php dev/Tools/mem/1.php $i|cut -f 2 -d:|sed -r 's/^$/;/g'|sed -r 's/([0-9]+)$/\1,/g'|tr -d '\n'; echo $i; done)|tr -d '\n'|sed -r 's/$/]/g'|sed -r 's/^;/[/g'>php7.m
//Large Programs
(for i in $(seq 0 50 100000);do php5 dev/Tools/mem/1.php $i|cut -f 2 -d:|sed -r 's/^$/;/g'|sed -r 's/([0-9]+)$/\1,/g'|tr -d '\n'; echo $i; done)|tr -d '\n'|sed -r 's/$/]/g'|sed -r 's/^;/[/g'>php5.m    
(for i in $(seq 0 50 100000);do php dev/Tools/mem/1.php $i|cut -f 2 -d:|sed -r 's/^$/;/g'|sed -r 's/([0-9]+)$/\1,/g'|tr -d '\n'; echo $i; done)|tr -d '\n'|sed -r 's/$/]/g'|sed -r 's/^;/[/g'>php7.m

октавный ящик

php7;php7=ans;
php5;php5=ans;
plot(php5(:,5)',[php5(:,1:4)';php7(:,1:4)']');
legend("PHP5 mgu", "PHP5 rmu", "PHP5 rpmu", "PHP5 pmu","PHP7 mgu", "PHP7 rmu", "PHP7 rpmu", "PHP7 pmu");

Подробнее

Ответ 2

Ваши тесты показывают больше использования памяти в PHP 7.0, потому что код тестирования очень прост.

Известно, что PHP 7.0 использует меньше памяти (и быстрее), чем PHP 5.6 из-за радикальной перезаписи внутреннего ZEND Engine (ядро интерпретатора)

Как Gordon, скорее всего, новые функции и улучшения в PHP 7.0 требуют "начальной загрузки", что приводит к отрицательным результатам при тестировании на небольших фрагментах кода.

Попробуйте сделать что-то более сложное: постройте массив из 10.000 целых чисел, затем отсортируйте его, используя Quicksort algorythm.

Вот результат:

PHP 7.0

Memory Usage: 1432752
Real Memory Usage: 4194304
Real Peak Memory Usage: 4194304
Peak Memory Usage: 3152360


PHP 5.6

Memory Usage: 2756744
Real Memory Usage: 4980736
Real Peak Memory Usage: 6029312
Peak Memory Usage: 5710464

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

Я проверил тест на http://phptester.net

Ниже приведен код

<?php
function quick_sort($array)
{
    $length = count($array);
    $pivot = $array[0];
    $left = $right = array();
    for($i = 1; $i < count($array); $i++)
    {
        if($array[$i] < $pivot)
        {
            $left[] = $array[$i];
        }
        else
        {
            $right[] = $array[$i];
        }
    }
    return array_merge(quick_sort($left), array($pivot), quick_sort($right));
}

$unsorted = array();
for($i=0;$i<10000;$i++)
{
    $unsorted[] = rand(1,1000000);
}

$sorted = quick_sort($unsorted);

$lf = "<br/>";

echo $lf;
echo "Memory Usage: ".memory_get_usage();
echo $lf;
echo "Real Memory Usage: ".memory_get_usage(true);
echo $lf;
echo "Real Peak Memory Usage: ".memory_get_peak_usage(true);
echo $lf;
echo "Peak Memory Usage: ".memory_get_peak_usage();
echo $lf;

Кредит для алгоритма quicksort в PHP: http://andrewbaxter.net/quicksort.php

Ответ 3

Upfront Я хочу сказать, что если вы видите более высокий уровень использования памяти в PHP 7 на реальном коде, наиболее вероятной причиной является то, что PHP 7 будет сообщать использование памяти буферизованных запросов mysqlnd как часть использования памяти. В PHP 5 это использование памяти не сообщалось (но, разумеется, память все еще использовалась). Для больших запросов это может иметь очень существенную разницу.

Теперь к вашему фактическому случаю, который в основном относится к использованию памяти PHP сразу после запуска запроса. ответ MobDev уже объясняет, почему существует расхождение в "реальном" использовании памяти, которое является метрикой использования памяти, которая сообщает, сколько памяти PHP-распределитель запросил у системы распределитель ядра. Как указывает MobDev, PHP 7 будет выделять память на более крупные куски (2 МБ), а также более агрессивно относится к кэшированию выделенных блоков.

Однако это не объясняет расхождения в "нереальном" использовании памяти, что не учитывает данные распределителя. Легко проверить, идет ли речь о памяти, используя профилировщик памяти, например. запустив PHP через USE_ZEND_ALLOC=0 valgrind --tool=massif. Часть USE_ZEND_ALLOC=0 указывает PHP не использовать собственный распределитель.

Прежде всего, это покажет вам, что фактическое использование памяти и использование памяти, описанное в PHP, значительно отличаются. Massif покажет использование 3.2MB для PHP 5.6 и 2.3MB для PHP 7. Причина в том, что PHP только сообщает память, которая проходит через его собственный распределитель (ZMM), в то время как многие структуры, которые выживают по нескольким запросам, не выделяются с помощью этого.

Самые большие распределения, проходящие через системный распределитель (таким образом, не сообщается в использовании памяти):

                       | PHP 5.6 | PHP 7
interned string buffer | 1 MB    | 150 KB + strings
GC buffer              | 320 KB  | 320 KB
internal classes/funcs | >1.3 MB | >0.5 MB

"Внутренние классы /funcs " - грубая нижняя граница, потому что здесь задействовано много небольших распределений, которые трудно подсчитать. Одно из основных различий видно, что PHP 7 не использует фиксированный интернированный строковый буфер (указанный размер является для буфера хэш-таблицы, который я вижу, который не включает размер самих строк).

Однако это все еще не отвечает на вопрос о фактическом использовании памяти. В этом случае наибольшие распределения:

             | PHP 5.6 | PHP 7
VM stack     | 130 KB  | 256 KB
Object store | 64 KB   | (8 KB)
CG arena     | ---     | 64 KB

Здесь есть пара различий. Главное, что PHP 7 использует больший размер страницы VM (примерно в два раза больше). Кроме того, PHP 7 использует арену для хранения определенных структур (например, пользовательских функций), которая начинается с размера по умолчанию 64 КБ. С другой стороны, размер буфера хранилища объектов значительно меньше в PHP 7.

Таким образом, ответ TL, DR заключается в том, что PHP 7 использует больший размер страницы стека VM.

Ответ 4

Php 5.6 требует меньше байтов по сравнению с Php 7.0.