memory_get_peak_usage () mit "realer Verwendung"

91

Wenn das real_usageArgument auf truePHP DOCS gesetzt ist, wird die tatsächliche Größe des vom System zugewiesenen Speichers abgerufen. Wenn dies der falseFall ist, wird der Speicher von gemeldetemalloc()

Welche dieser beiden Optionen gibt die max. Speicher relativ zum Speichergrenzwert in php.ini zugewiesen?

Ich möchte wissen, wie nahe das Skript war, um diese Grenze zu erreichen.

thelolcat
quelle
8
Ich möchte Sie auf eine Präsentation von Julien Pauli youtube.com/watch?v=sm1HUrnsxLI für die PHP UK-Konferenz 2013 verweisen , in der er darüber spricht, wie Speicher in PHP funktioniert.
mpratt

Antworten:

136

Ok, lassen Sie uns dies mit einem einfachen Skript testen:

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
}

Ausgabe:

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

Die tatsächliche Nutzung scheint der vom System zugewiesene Speicher zu sein, der in größeren Buckets zugewiesen zu werden scheint, als derzeit vom Skript benötigt werden. (Ich denke aus Leistungsgründen). Dies ist auch der Speicher, den der PHP-Prozess verwendet.

Die $real_usage = falseVerwendung ist die Speicherauslastung, die Sie tatsächlich in Ihrem Skript verwendet haben, nicht die tatsächliche Speichermenge, die vom Speichermanager von Zend zugewiesen wurde.

Lesen Sie diese Frage für weitere Informationen.

Kurz gesagt: Um zu erreichen, wie nahe Sie an der Speichergrenze sind, verwenden Sie $real_usage = true

Niko Sams
quelle
5
Die Zend-Engine weist Speicher in 256-KB-Blöcken zu. Der Wert für die "tatsächliche Verwendung" ist die Summe aller dieser Blöcke. Das ist eigentlich der Wert, der verwendet wird, um den Speicherausfallfehler auszulösen : if (segment_size < true_size || heap->real_size + segment_size > heap->limit) { /* Memory limit overflow */.
Cleong
2
Der "nicht reelle" Wert ist die Summe der Anzahl der Bytes, die von Aufrufen an angefordert werden emalloc(plus Bytes für Header und Speicherausrichtung). Es spiegelt nicht den Speicher wider, der aufgrund von Blöcken verschwendet wurde, die nicht in den in bereits zugewiesenen Segmenten verbleibenden Speicherplatz passen. Wenn Sie Ihr Beispiel ändern, um (1024 * 256) Bytes und ein 2M-Limit zuzuweisen, wird der Unterschied zwischen zwei deutlicher.
Cleong
@Niko, warum hast du memory_get_peak_usage anstelle von memory_get_usage verwendet? Sollten wir nicht gc_disable () verwenden und memory_get_usage verwenden, um ein genaueres Ergebnis zu erhalten?
Pacerier
@ Pacerier die Frage war, wie nahe an der Grenze das Skript ist - für diesen Höhepunkt macht Sinn, würde ich sagen
Niko Sams
4
Wie @cleong erklärt hat, ist diese Antwort trotz aller positiven Stimmen tatsächlich falsch. Der memory_get_usage(true)Rückgabewert, mit dem verglichen werden soll memory_limit. Das Beispiel in der Antwort ist viel zu einfach, da kein "verschwendeter" Speicher "vorhanden ist. Was passiert, ist, dass der" echte "zugewiesene Speicher von" 1 MiB "auf" 1,25 MiB "erhöht werden muss, was den schwerwiegenden Fehler auslöst Ich habe ein komplexes Batch-Skript mit einem Speicherlimit von 120 MiB, das "nicht real" zugewiesenen Speicher von nur "80 MiB" hat, wenn es abgebrochen wird, weil der "real" zugewiesene Speicher das Limit erreicht.
Martin Prikryl
36

Einführung

Sie sollten verwenden, memory_get_usage(false)weil Sie Speicher verwenden möchten, nicht Speicher zugewiesen.

Was ist der Unterschied

Ihre Google MailMacht hat zugewiesen 25MBSpeicher für Sie , aber es bedeutet nicht , dass das , was Sie im Moment verwendet haben.

Genau das hat das PHP-Dokument gesagt

Setzen Sie dies auf TRUE, um die tatsächliche Größe des vom System zugewiesenen Speichers zu erhalten. Wenn nicht gesetzt oder FALSE, wird nur der von emalloc () verwendete Speicher gemeldet.

Beide Argumente würden den relativ zum Speicherlimit zugewiesenen Speicher zurückgeben, aber der Hauptunterschied ist:

memory_get_usage(false)Geben Sie den von emalloc()while verwendeten Speicher an, der den memory_get_usage(true)Meilenstein zurückgibt. Dies kann hier im Memory Mile Store demonstriert werden

Ich möchte wissen, wie nahe das Skript war, um diese Grenze zu erreichen.

Das würde einige Mathematik erfordern und möglicherweise nur in Schleifen oder bestimmten Anwendungsfällen funktionieren. Warum habe ich so gesagt?

Vorstellen

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.

Soweit ich weiß, kann ich den für eine Variable oder einen bestimmten Abschnitt von PHP verwendeten Speicher nur überprüfen:

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

Siehe Erläuterung . Wenn Sie sich jedoch in einer Schleife oder einer rekursiven Funktion befinden, können Sie die maximale Speichernutzung verwenden, um sicher zu schätzen, wann ein Speicher-Peek erreicht wird.

Beispiel

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
}

Ausgabe

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

Live-Demo

Dies kann immer noch fehlschlagen

Es kann fehlschlagen, da danach if ($percentage > $peekPoint) { noch noch zusätzliche Aufgaben zu erledigen sind, die ebenfalls Speicher verbrauchen

        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.

Fazit

Es ist keine perfekte Lösung, aber prüfen Sie in regelmäßigen Abständen, ob Speicher vorhanden ist, und prüfen Sie exitsofort, ob der Blick größer ist (z. B. 90%), und lassen Sie das schicke Zeug zurück

Baba
quelle
Ist memory_limitOption über Haufen? oder stapeln?
Yousha Aleayoub
Was ist, wenn ich zwei Skripte parallel oder viele Anfragen habe? Gibt die Funktion memory_get_usage () den Speicher zurück, der für alle gleichzeitig ausgeführten Skripte verwendet wird, oder nur für das eigentliche Skript?
Mohammed Yassine CHABLI
7

real_usagefalsche Berichte die Verwendung Ihr Skript verwendet . Dies wird die genauere von beiden sein.

real_usagetrue meldet den Ihrem Skript zugewiesenen Speicher . Dies wird der höhere von beiden sein.

Ich würde es wahrscheinlich verwenden, truewenn ich versuchen würde zu vergleichen, da Ihrem Skript niemals mehr als das Speicherlimit zugewiesen würde und es weiterhin ausgeführt würde, solange es (plus alle anderen Skripte) diese Verwendung nicht überschreitet.

Glitch Desire
quelle
1
Es ist genau das Gegenteil: falseIst der Speicher, den das Skript verwendet , trueist der Speicher zugewiesen .
Benjamin
1
@ Benjamin Ja, ich bin mir nicht sicher, warum ich das so blind falsch verstanden habe. Ähm, behoben.
Glitch Desire
2

gemäß PHP memory_get_usage

real_usage

Setzen Sie dies auf TRUE, um den vom System zugewiesenen Gesamtspeicher einschließlich nicht verwendeter Seiten abzurufen. Wenn nicht gesetzt oder FALSE, wird nur der verwendete Speicher gemeldet.

Um den von Ihrem Skript verwendeten Speicher zu erhalten, sollten Sie memory_get_usage () verwenden, da standardmäßig real_usage false ist.

Wenn Sie den vom System zugewiesenen Speicher erhalten möchten, sich aber nicht darum kümmern, wie viel tatsächlich verwendet wurde, verwenden Sie memory_get_usage (true).

Tofeeq
quelle
-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;
?>
Rahul Rohewal
quelle
1
Willkommen bei Stackoverflow! Könnten Sie uns bitte sagen, wie die Antwort lautet? Nicht nur der Code, sondern auch, wie Sie herausgefunden haben, wie Sie die Frage beheben können. Vielen Dank!
Gilles Heinesch
Ihre Antwort enthält möglicherweise einige potenziell nützliche Informationen, ist jedoch für die gestellte Frage nicht relevant. Vielleicht möchten Sie erklären, wie sich Ihre Antwort auf die gestellte Frage bezieht.
Moritur