memory_get_peak_usage () с «реальным использованием»

94

Если real_usageаргумент установлен trueв PHP DOCS, говорят, что он получит реальный размер памяти, выделенной из системы. Если это falseбудет информация о памятиemalloc()

Какой из этих двух вариантов возвращает макс. память, выделенная относительно значения ограничения памяти в php.ini?

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

thelolcat
источник
8
Я хотел бы указать вам на презентацию Жюльена Паули youtube.com/watch?v=sm1HUrnsxLI на конференции php uk 2013, где он рассказывает о том, как работает память внутри PHP.
mpratt
Также см stackoverflow.com/a/7234026/632951
Pacerier

Ответы:

138

Хорошо, давайте проверим это с помощью простого скрипта:

ini_set('memory_limit', '1M');
$x = '';
while(true) {
  echo "not real: ".(memory_get_peak_usage(false)/1024/1024)." MiB\n";
  echo "real: ".(memory_get_peak_usage(true)/1024/1024)." MiB\n\n";
  $x .= str_repeat(' ', 1024*25); //store 25kb more to string
}

Выход:

not real: 0.73469543457031 MiB
real: 0.75 MiB

not real: 0.75910949707031 MiB
real: 1 MiB

...

not real: 0.95442199707031 MiB
real: 1 MiB

not real: 0.97883605957031 MiB
real: 1 MiB

PHP Fatal error:  Allowed memory size of 1048576 bytes exhausted (tried to allocate 793601 bytes) in /home/niko/test.php on line 7

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

$real_usage = falseИспользование является использование памяти вы на самом деле используется в сценарии, а не фактический объем памяти , выделенный менеджером памяти Zend.

Прочтите этот вопрос для получения дополнительной информации.

Вкратце: чтобы узнать, насколько вы приблизились к пределу памяти, используйте $real_usage = true

Нико Самс
источник
5
Механизм Zend выделяет память блоками по 256 КБ. Значение «реального использования» - это сумма всех этих фрагментов. Это на самом деле значение , используемое , чтобы вызвать ошибку исчерпания памяти: if (segment_size < true_size || heap->real_size + segment_size > heap->limit) { /* Memory limit overflow */.
cleong
2
«Не реальное» значение - это сумма количества байтов, запрошенных вызовами emalloc(плюс байты для заголовков и выравнивания памяти). Он не отражает потери памяти из-за того, что блоки не помещаются в пространство, оставшееся в уже выделенных сегментах. Если вы измените свой пример на выделение (1024 * 256) байтов и ограничение 2M, разница в два станет более очевидной.
cleong
@Niko, почему ты использовал memory_get_peak_usage вместо memory_get_usage? Разве мы не должны использовать gc_disable () и memory_get_usage, чтобы получить более точный результат?
Pacerier
@Pacerier, вопрос заключался в том, насколько близок к пределу сценарий - я бы сказал, что этот пик имеет смысл
Нико Сэмс
4
Как объяснил @cleong, этот ответ на самом деле неверен, несмотря на все положительные голоса. memory_get_usage(true)Значение возвращается , которые должны быть сопоставлены с memory_limit. Пример, приведенный в ответе, слишком прост, поскольку нет «потраченной впустую» памяти. Происходит то, что «реальную» выделенную память необходимо увеличить с «1 МБ» до «1,25 МБ», и это вызывает фатальную ошибку. . у меня есть сложный пакетный скрипт с лимитом памяти 120 Мбайт , которые имеют «не реально» выделенную память только «80 МиБа» , когда она будет прервана , так как «реальная» выделенная память достигает предел.
Мартин Přikryl
37

Введение

Вы должны использовать, memory_get_usage(false)потому что вы хотите использовать память, а не выделенную память.

Какая разница

Ваша Google Mailмощь распределили 25MBхранения для вас , но это не значит , что это то , что вы использовали в данный момент.

Это именно то, что говорилось в документе PHP

Установите значение TRUE, чтобы получить реальный размер памяти, выделенной системой. Если не установлено или FALSE, сообщается только память, используемая emalloc ().

Оба аргумента будут возвращать память, выделенную относительно лимита памяти, но главное отличие:

memory_get_usage(false)указать объем памяти, используемый в emalloc()то время как memory_get_usage(true)возвращает веху, которую можно продемонстрировать здесь Memory Mile Store

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

Это потребует некоторой математики и может работать только в циклах или определенных случаях использования. Почему я так сказал?

Представить

ini_set('memory_limit', '1M');
$data = str_repeat(' ', 1024 * 1024);

The above script would fail before you even get the chance to start start checking memory.

Насколько я знаю, единственный способ проверить память, используемую для переменной или определенного раздела PHP:

$start_memory = memory_get_usage();
$foo = "Some variable";
echo memory_get_usage() - $start_memory;

См. Объяснение , но если вы находитесь в цикле или рекурсивной функции, вы можете использовать максимальное использование памяти, чтобы безопасно оценить, когда будет достигнут просмотр памяти.

пример

ini_set('memory_limit', '1M');

$memoryAvailable = filter_var(ini_get("memory_limit"), FILTER_SANITIZE_NUMBER_INT);
$memoryAvailable = $memoryAvailable * 1024 * 1024;

$peekPoint = 90; // 90%

$memoryStart = memory_get_peak_usage(false);
$memoryDiff = 0;

// Some stats
$stat = array(
        "HIGHEST_MEMORY" => 0,
        "HIGHEST_DIFF" => 0,
        "PERCENTAGE_BREAK" => 0,
        "AVERAGE" => array(),
        "LOOPS" => 0
);

$data = "";
$i = 0;
while ( true ) {
    $i ++;

    // Get used memory
    $memoryUsed = memory_get_peak_usage(false);

    // Get Diffrence
    $memoryDiff = $memoryUsed - $memoryStart;

    // Start memory Usage again
    $memoryStart = memory_get_peak_usage(false);

    // Gather some stats
    $stat['HIGHEST_MEMORY'] = $memoryUsed > $stat['HIGHEST_MEMORY'] ? $memoryUsed : $stat['HIGHEST_MEMORY'];
    $stat['HIGHEST_DIFF'] = $memoryDiff > $stat['HIGHEST_DIFF'] ? $memoryDiff : $stat['HIGHEST_DIFF'];
    $stat['AVERAGE'][] = $memoryDiff;
    $stat['LOOPS'] ++;
    $percentage = (($memoryUsed + $stat['HIGHEST_DIFF']) / $memoryAvailable) * 100;

    // var_dump($percentage, $memoryDiff);

    // Stop your scipt
    if ($percentage > $peekPoint) {

        print(sprintf("Stoped at: %0.2f", $percentage) . "%\n");
        $stat['AVERAGE'] = array_sum($stat['AVERAGE']) / count($stat['AVERAGE']);
        $stat = array_map(function ($v) {
            return sprintf("%0.2f", $v / (1024 * 1024));
        }, $stat);
        $stat['LOOPS'] = $i;
        $stat['PERCENTAGE_BREAK'] = sprintf("%0.2f", $percentage) . "%";
        echo json_encode($stat, 128);
        break;
    }

    $data .= str_repeat(' ', 1024 * 25); // 1kb every time
}

Выход

Stoped at: 95.86%
{
    "HIGHEST_MEMORY": "0.71",
    "HIGHEST_DIFF": "0.24",
    "PERCENTAGE_BREAK": "95.86%",
    "AVERAGE": "0.04",
    "LOOPS": 11
}

Живая демонстрация

Это все еще может потерпеть неудачу

Это может привести к сбою, потому что после if ($percentage > $peekPoint) { этого все еще добавляется дополнительная задача, которая также потребляет память

        print(sprintf("Stoped at: %0.2f", $percentage) . "%\n");
        $stat['AVERAGE'] = array_sum($stat['AVERAGE']) / count($stat['AVERAGE']);
        $stat = array_map(function ($v) {
            return sprintf("%0.2f", $v / (1024 * 1024));
        }, $stat);
        $stat['LOOPS'] = $i;
        $stat['PERCENTAGE_BREAK'] = sprintf("%0.2f", $percentage) . "%";
        echo json_encode($stat, 128);
        break;

If the memory to process this request is grater than the memory available the script would fail.

Вывод

Это не идеальное решение, но проверяйте память с интервалом и, если она превышает, exitмгновенно просматривайте (например, 90%) и оставляйте причудливые вещи

Баба
источник
Есть memory_limitвариант насчет кучи? или стек?
Yousha Aleayoub
что, если у меня есть два параллельных сценария или много запросов, функция memory_get_usage () возвращает память, используемую для всех этих сценариев, выполняемых в одно и то же время, или только фактического сценария?
Мохаммед Яссин ЧАБЛИ
7

real_usageложные сообщения об использовании сценария используется . Это будет более точным из двух.

real_usagetrue сообщает об объеме памяти, выделенной вашему скрипту. Это будет более высокий из двух.

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

Глитч-желание
источник
1
Это как раз наоборот: falseэто память сценарий используется , trueэто память выделяется .
Бенджамин
1
@ Бенджамин Да, не знаю, почему я так слепо ошибался. Умм, исправлено.
Glitch Desire
2

согласно PHP memory_get_usage

real_usage

Установите значение TRUE, чтобы получить общий объем памяти, выделенной системой, включая неиспользуемые страницы. Если не установлен или FALSE, сообщается только использованная память.

поэтому, чтобы получить память, используемую вашим скриптом, вы должны использовать memory_get_usage (), поскольку по умолчанию real_usage имеет значение false.

если вы хотите получить память, выделенную системой, но не заботитесь о том, сколько фактически было использовано, используйте memory_get_usage (true);

Tofeeq
источник
0
<!-- Print CPU memory and load -->
<?php
$output = shell_exec('free');
$data = substr($output,111,19);
echo $data;
echo file_get_contents('/proc/loadavg');
$load = sys_getloadavg();
$res = implode("",$load);
echo $res;
?>
Рахул Рохевал
источник
2
Добро пожаловать в Stackoverflow! не могли бы вы рассказать нам, каков ответ? Не только код, но и то, как вы придумали, как исправить вопрос. Благодарность!
Gilles Heinesch
Хотя ваш ответ может предоставить некоторую потенциально полезную информацию, он не имеет отношения к задаваемому вопросу. Возможно, вы захотите объяснить, как ваш ответ соотносится с задаваемым вопросом.
Моритур