memory_get_peak_usage () z „rzeczywistym użyciem”


94

Jeśli real_usageargument jest ustawiony truena PHP DOCS, powiedz, że uzyska rzeczywisty rozmiar pamięci przydzielonej z systemu. Jeśli tak, falseotrzyma raport o pamięciemalloc()

Która z tych 2 opcji zwraca maks. pamięć przydzielona względem wartości limitu pamięci w php.ini?

Chcę wiedzieć, jak blisko było osiągnięcie tego limitu przez skrypt.


8
Chciałbym wskazać na prezentację Juliena Pauliego youtube.com/watch?v=sm1HUrnsxLI na konferencję php uk 2013, w której opowiada o tym, jak działa pamięć w PHP.
mpratt

Odpowiedzi:


138

Ok, przetestujmy to za pomocą prostego skryptu:

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
}

Wynik:

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

Wygląda na to, że rzeczywiste użycie to pamięć przydzielona przez system - która wydaje się być przydzielana w większych pojemnikach niż obecnie wymagane przez skrypt. (Myślę, że ze względu na wydajność). Jest to również pamięć używana przez proces php.

$real_usage = falseUżycie jest użycie pamięci faktycznie wykorzystane w skrypcie, a nie rzeczywista ilość pamięci przydzielonej przez menedżera pamięci Zend za.

Przeczytaj to pytanie, aby uzyskać więcej informacji.

W skrócie: aby zobaczyć, jak blisko jesteś limitu pamięci, użyj $real_usage = true


5
Silnik Zend przydziela pamięć na 256K porcjach. Wartość „rzeczywistego użycia” to suma wszystkich tych fragmentów. To rzeczywiście wartość używana do wywołać błąd wyczerpanie pamięci: if (segment_size < true_size || heap->real_size + segment_size > heap->limit) { /* Memory limit overflow */.
cleong

2
Wartość „nie rzeczywista” jest sumą liczby bajtów żądanych przez wywołania emalloc(plus bajty dla nagłówków i wyrównania pamięci). Nie odzwierciedla zmarnowanej pamięci z powodu bloków nie mieszczących się w przestrzeni pozostałej w już przydzielonych segmentach. Jeśli zmienisz przykład, aby przydzielić (1024 * 256) bajtów i limit 2M, różnica dwóch stanie się bardziej widoczna.
cleong

@Niko, dlaczego użyłeś memory_get_peak_usage zamiast memory_get_usage? Czy nie powinniśmy użyć gc_disable () i użyć memory_get_usage, aby uzyskać dokładniejszy wynik?
Pacerier,

@Pacerier pytanie brzmiało, jak blisko granicy znajduje się scenariusz - powiedziałbym, że ten szczyt ma sens
Niko Sams

4
Jak wyjaśnił @cleong, pomimo wszystkich pozytywnych głosów ta odpowiedź jest w rzeczywistości błędna. memory_get_usage(true)Wartość zwrotów, które powinny być w porównaniu do memory_limit. Przykład podany w odpowiedzi jest zbyt prosty, ponieważ nie ma „zmarnowanej” pamięci. Dzieje się tak, że „rzeczywistą” przydzieloną pamięć należy zwiększyć z „1 MiB” do „1,25 MiB” i to właśnie powoduje błąd krytyczny Mam złożony skrypt wsadowy z limitem pamięci 120 MB, który ma "nie rzeczywistą" przydzieloną pamięć wynoszącą tylko "80 MB", gdy jest przerywana, ponieważ "prawdziwa" przydzielona pamięć osiąga limit.
Martin Prikryl

37

Wprowadzenie

Powinieneś użyć, memory_get_usage(false)ponieważ to, czego chcesz, to pamięć używana, a nie przydzielona.

Co za różnica

Być Google Mailmoże przeznaczyłeś 25MBdla Ciebie miejsce na dane, ale nie oznacza to, że właśnie tego używałeś.

Dokładnie to mówi dokument PHP

Ustaw to na TRUE, aby uzyskać rzeczywisty rozmiar pamięci przydzielonej z systemu. Jeśli nie jest ustawione lub FALSE, raportowana jest tylko pamięć używana przez emalloc ().

Oba argumenty zwróciłyby pamięć przydzieloną względem limitu pamięci, ale główna różnica jest taka:

memory_get_usage(false)Podaj pamięć używaną przez emalloc()while memory_get_usage(true)zwraca kamień milowy, który można zademonstrować tutaj Memory Mile Store

Chcę wiedzieć, jak blisko było osiągnięcie tego limitu przez skrypt.

Wymagałoby to trochę matematyki i może działać tylko w pętlach lub w określonych przypadkach użycia. Dlaczego tak powiedziałem?

Wyobrażać sobie

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.

O ile wiem, jedynym sposobem na sprawdzenie pamięci używanej dla zmiennej lub określonej sekcji PHP jest:

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

Zobacz Wyjaśnienie , ale jeśli jesteś w pętli lub funkcji rekurencyjnej, możesz użyć maksymalnego użycia pamięci, aby bezpiecznie oszacować, kiedy zostanie osiągnięty wgląd w pamięć.

Przykład

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
}

Wynik

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

Live Demo

To wciąż może się nie powieść

Może się nie powieść, ponieważ po if ($percentage > $peekPoint) { tym nadal dodaj, aby wykonać dodatkowe zadanie, a także zużywa pamięć

        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.

Wniosek

Nie jest to idealne rozwiązanie, ale sprawdzaj pamięć co jakiś czas i jeśli przekracza ona peek (np. 90%) exitnatychmiast i zostaw wymyślne rzeczy


Czy memory_limitopcja dotyczy sterty? lub stos?
Yousha Aleayoub

co się stanie, jeśli mam dwa skrypty równolegle lub wiele żądań, czy funkcja memory_get_usage () zwraca pamięć używaną przez wszystkie te skrypty wykonywane w tym samym czasie lub tylko sam skrypt?
Mohammed Yassine CHABLI

7

real_usagefałszywe raporty sposób użycia skrypt używany . Będzie to dokładniejsze z dwóch.

real_usagetrue informuje o pamięci przydzielonej skryptu. Będzie to wyższa z dwóch.

Prawdopodobnie użyłbym, truegdybym próbował porównać, ponieważ twój skrypt nigdy nie zostałby przydzielony więcej niż limit pamięci i działałby tak długo, jak długo (plus wszystkie inne skrypty) nie przekraczałby tego użycia.


1
Jest dokładnie odwrotnie: falsejest pamięcią używaną przez skrypt , truejest pamięcią przydzieloną .
Benjamin,

1
@Benjamin Tak, nie jestem pewien, dlaczego tak ślepo się pomyliłem. Umm, naprawiono.
Glitch Desire

2

zgodnie z PHP memory_get_usage

real_usage

Ustaw na TRUE, aby uzyskać całkowitą ilość pamięci przydzielonej przez system, w tym nieużywane strony. Jeśli nie jest ustawiona lub FALSE, raportowana jest tylko używana pamięć.

więc aby uzyskać pamięć używaną przez twój skrypt, powinieneś użyć memory_get_usage (), ponieważ domyślnie real_usage ma wartość false.

jeśli chcesz uzyskać pamięć przydzieloną przez system, ale nie obchodzi cię, ile faktycznie zostało wykorzystane, użyj memory_get_usage (true);


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
Witamy w Stackoverflow! czy możesz nam powiedzieć, jaka jest odpowiedź? Nie tylko kod, ale także sposób, w jaki rozwiązałeś to pytanie. Dzięki!
Gilles Heinesch

Chociaż Twoja odpowiedź może dostarczyć potencjalnie przydatnych informacji, nie ma ona związku z zadawanym pytaniem. Możesz chcieć wyjaśnić, jak twoja odpowiedź odnosi się do zadanego pytania.
Moritur
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.