memory_get_peak_usage () з “реальним використанням”


91

Якщо real_usageаргумент встановлений trueяк PHP DOCS, скажімо, він отримає реальний розмір пам'яті, виділеної із системи. Якщо це такfalse це отримає пам'ять, про яку повідомляєemalloc()

Який із цих 2 варіантів повертає макс. пам'ять, виділена щодо граничного значення пам'яті у php.ini?

Я хочу знати, наскільки близьким був сценарій, щоб досягти цієї межі.


8
Я хотів би вказати вам на презентацію Жульєна Паулі youtube.com/watch?v=sm1HUrnsxLI для конференції php uk 2013, де він розповідає про те, як працює пам’ять у PHP.
mpratt

Відповіді:


136

Добре, давайте перевіримо це за допомогою простого скрипту:

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 виділяє пам’ять у 256K фрагментів. Значення "реального використання" - це сума всіх цих фрагментів. Це на самому ділі значення , яке використовується , щоб викликати помилку вичерпання пам'яті: if (segment_size < true_size || heap->real_size + segment_size > heap->limit) { /* Memory limit overflow */.
Клеонг

2
Значення "не реальне" - це сума кількості байтів, запитуваних викликами emalloc(плюс байти для заголовків та вирівнювання пам'яті). Він не відображає витрачену пам’ять через невміщення блоків у простір, що залишився у вже виділених сегментах. Якщо ви зміните свій приклад на виділення (1024 * 256) байтів і обмеження 2 М, різниця в двох стане більш очевидною.
Клеонг

@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 Мб", коли вона переривається, оскільки "реальна" виділена пам'ять досягає межі.
Мартін Прикрил,

36

Вступ

Ви повинні використовувати memory_get_usage(false) оскільки те, що ви хочете, це пам'ять, яка не виділена.

Яка різниця

Можливо, Google Mailви виділили 25MBдля вас місце для зберігання, але це не означає, що цим ви зараз користуєтесь.

Це саме те, що говорив документ PHP

Встановіть значення TRUE, щоб отримати реальний обсяг пам'яті, виділений із системи. Якщо не встановлено або FALSE, повідомляється лише про пам’ять, що використовується emalloc ().

Обидва аргументи повертають пам’ять, виділену щодо обмеження пам’яті, але головна різниця полягає в:

memory_get_usage(false)надайте пам’ять, яку використовує emalloc()while, 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

справжнє_використання

Встановіть значення TRUE, щоб отримати загальну пам’ять, виділену системою, включаючи невикористані сторінки. Якщо не встановлено або FALSE, повідомляється лише про використовувану пам’ять.

отже, щоб отримати пам'ять, яку використовує ваш сценарій, ви повинні використовувати memory_get_usage (), оскільки за замовчуванням real_usage не відповідає.

якщо ви хочете отримати пам'ять, виділену системою, але вам не важливо, скільки насправді було використано, використовуйте memory_get_usage (true);


-1
<!-- 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;
?>

1
Ласкаво просимо до Stackoverflow! не могли б ви сказати нам, що таке відповідь? Не тільки код, але й те, як ви зрозуміли, як вирішити питання. Дякую!
Gilles Heinesch,

Незважаючи на те, що ваша відповідь може надати деяку потенційно корисну інформацію, вона не має відношення до запитуваного питання. Можливо, ви захочете пояснити, як ваша відповідь пов’язана із запитаним запитанням.
Морітур
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.