memory_get_peak_usage () con "uso real"

93

Si el real_usageargumento se establece en truePHP DOCS, digamos que obtendrá el tamaño real de la memoria asignada del sistema. Si lo es false, obtendrá la memoria informada poremalloc()

¿Cuál de estas 2 opciones devuelve el máx. memoria asignada en relación con el valor límite de memoria en php.ini?

Quiero saber qué tan cerca estuvo el guión de alcanzar ese límite.

thelolcat
fuente
8
Me gustaría señalarles una presentación de Julien Pauli youtube.com/watch?v=sm1HUrnsxLI para la conferencia php uk 2013, donde habla sobre cómo funciona la memoria dentro de PHP.
mpratt
También vea stackoverflow.com/a/7234026/632951
Pacerier

Respuestas:

137

Ok, probemos esto usando un script simple:

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
}

Salida:

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

Parece que el uso real es la memoria asignada desde el sistema, que parece asignarse en depósitos más grandes que los que necesita actualmente el script. (Supongo que por razones de rendimiento). Esta es también la memoria que usa el proceso php.

El $real_usage = falseuso es el uso de memoria que realmente usó en su script, no la cantidad real de memoria asignada por el administrador de memoria de Zend.

Lea esta pregunta para obtener más información.

En resumen: para saber qué tan cerca está del límite de memoria, use $real_usage = true

Niko Sams
fuente
5
El motor Zend asigna memoria en trozos de 256K. El valor de "uso real" es la suma de todos estos fragmentos. Eso es en realidad el valor utilizado para desencadenar el error de agotamiento de la memoria: if (segment_size < true_size || heap->real_size + segment_size > heap->limit) { /* Memory limit overflow */.
Cleong
2
El valor "no real" es la suma del número de bytes solicitados por las llamadas a emalloc(más bytes para encabezados y alineación de memoria). No refleja el desperdicio de memoria debido a que los bloques no encajan en el espacio restante en los segmentos ya asignados. Si cambia su ejemplo para asignar (1024 * 256) bytes y un límite de 2M, la diferencia de dos se hará más evidente.
Cleong
@Niko, ¿Por qué usaste memory_get_peak_usage en lugar de memory_get_usage? ¿No deberíamos gc_disable () y usar memory_get_usage para obtener un resultado más preciso?
Pacerier
@Pacerier, la pregunta era saber qué tan cerca del límite está el guión, porque ese pico tiene sentido, diría yo
Niko Sams
4
Como ha explicado @cleong, esta respuesta es realmente incorrecta, a pesar de todos los votos a favor. El memory_get_usage(true)valor de las devoluciones que se debe comparar a memory_limit. El ejemplo dado en la respuesta es demasiado simple ya que no hay "memoria desperdiciada". Lo que sucede es que la memoria asignada "real" debe aumentarse de "1 MiB" a "1.25 MiB" y eso es lo que desencadena el error fatal . Tengo un script por lotes complejo con un límite de memoria de 120 MiB que tiene una memoria asignada "no real" de solo "80 MiB" cuando se cancela porque la memoria asignada "real" alcanza el límite.
Martin Prikryl
36

Introducción

Debe usar memory_get_usage(false)porque lo que quiere es memoria usada, no memoria asignada.

Cual es la diferencia

Tu Google Mailpodrías haber asignado25MB espacio de almacenamiento para usted, pero eso no significa que sea lo que ha utilizado en este momento.

Esto es exactamente lo que decía el documento PHP

Establezca esto en TRUE para obtener el tamaño real de la memoria asignada desde el sistema. Si no se establece o es FALSE, solo se informa la memoria utilizada por emalloc ().

Ambos argumentos devolverían la memoria asignada en relación con el límite de memoria, pero la principal diferencia es:

memory_get_usage(false)dar la memoria utilizada por emalloc()mientras memory_get_usage(true)devuelve el hito que se puede demostrar aquí Memory Mile Store

Quiero saber qué tan cerca estuvo el guión de alcanzar ese límite.

Eso requeriría algunas matemáticas y podría funcionar solo en bucles o casos de uso específicos. ¿Por qué dije eso?

Imagina

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.

Hasta donde yo sé, la única forma en que puedo verificar la memoria utilizada para una variable o sección específica de PHP es:

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

Consulte la Explicación , pero si está en un bucle o en una función recursiva, puede usar el uso máximo de memoria para estimar de manera segura cuándo se alcanzaría el punto máximo de memoria.

Ejemplo

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
}

Salida

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

Demo en vivo

Esto todavía puede fallar

Puede fallar porque después de if ($percentage > $peekPoint) { esto todavía se agrega para hacer una tarea adicional con también consume memoria

        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.

Conclusión

No es una solución perfecta, pero verifique la memoria a intervalos y si excede la vista (por ejemplo, 90%) al exitinstante y deje las cosas elegantes

Baba
fuente
¿Es la memory_limitopción sobre el montón? o apilar?
Yousha Aleayoub
¿Qué pasa si tengo dos secuencias de comandos en paralelo o muchas solicitudes, di la función memory_get_usage () devuelve la memoria utilizada para todas las secuencias de comandos ejecutadas al mismo tiempo o solo la secuencia de comandos real?
Mohammed Yassine CHABLI
7

real_usagefalse informa el uso que utilizó su script . Este será el más preciso de los dos.

real_usagetrue informa la memoria asignada a su script. Este será el más alto de los dos.

Probablemente lo usaría truesi estuviera tratando de comparar, ya que a su script nunca se le asignará más que el límite de memoria y continuará ejecutándose siempre que (más todos los demás scripts) no exceda ese uso.

Glitch Desire
fuente
1
Es exactamente lo contrario: falsees la memoria que usa el script , truees la memoria asignada .
Benjamín
1
@Benjamin Sí, no estoy seguro de por qué me equivoqué tan ciegamente. Umm, arreglado.
Glitch Desire
2

según PHP memory_get_usage

real_usage

Ajústelo a TRUE para obtener la memoria total asignada del sistema, incluidas las páginas no utilizadas. Si no se establece o es FALSO, solo se informa la memoria utilizada.

por lo que para obtener la memoria utilizada por su script, debe usar memory_get_usage () ya que real_usage predeterminado es falso.

si desea obtener la memoria asignada por el sistema pero no le importa cuánto se usó realmente, use memory_get_usage (true);

Tofeeq
fuente
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;
?>
Rahul Rohewal
fuente
2
¡Bienvenido a Stackoverflow! ¿Podría decirnos cuál es la respuesta? No solo el código, sino también cómo descubrió cómo solucionar la pregunta. ¡Gracias!
Gilles Heinesch
Si bien su respuesta puede proporcionar información potencialmente útil, no es relevante para la pregunta que se hace. Es posible que desee explicar cómo se relaciona su respuesta con la pregunta que se hace.
Moritur