memory_get_peak_usage () com “uso real”

91

Se o real_usageargumento for definido como truePHP DOCS, diga que ele obterá o tamanho real da memória alocada do sistema. Se for false, irá obter a memória informada poremalloc()

Qual dessas 2 opções retorna o máximo. memória alocada em relação ao valor limite de memória no php.ini?

Quero saber o quão perto esteve o script de atingir esse limite.

Thelolcat
fonte
8
Gostaria de apontar para uma apresentação de Julien Pauli youtube.com/watch?v=sm1HUrnsxLI para a conferência php uk 2013, onde ele fala sobre como a memória funciona dentro do PHP.
mpratt
Consulte também stackoverflow.com/a/7234026/632951
Pacerier

Respostas:

136

Ok, vamos testar isso usando um script simples:

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
}

Resultado:

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 o uso real é a memória alocada do sistema - que parece ser alocada em depósitos maiores do que o atualmente necessário para o script. (Acho que por motivos de desempenho). Esta também é a memória que o processo php usa.

O $real_usage = falseuso é o uso de memória que você realmente usou em seu script, não a quantidade real de memória alocada pelo gerenciador de memória do Zend.

Leia esta pergunta para mais informações.

Resumindo: para saber o quão perto você está do limite de memória, use $real_usage = true

Niko Sams
fonte
5
O motor Zend aloca memória em blocos de 256K. O valor de "uso real" é a soma de todos esses blocos. Isso é realmente o valor usado para acionar o erro esgotamento da memória: if (segment_size < true_size || heap->real_size + segment_size > heap->limit) { /* Memory limit overflow */.
cleong
2
O valor "não real" é a soma do número de bytes solicitados por chamadas para emalloc(mais bytes para cabeçalhos e alinhamento de memória). Não reflete o desperdício de memória devido a blocos não cabendo no espaço restante em segmentos já alocados. Se você alterar seu exemplo para alocar (1024 * 256) bytes e um limite de 2M, a diferença de dois se tornará mais aparente.
cleong
@Niko, Por que você usou memory_get_peak_usage em vez de memory_get_usage? Não deveríamos gc_disable () e usar memory_get_usage para obter um resultado mais preciso?
Pacerier
@Pacerier a questão era chegar o quão perto do limite o script está - pois esse pico faz sentido, eu diria
Niko Sams
4
Como @cleong explicou, essa resposta está realmente errada, apesar de todos os votos positivos. O memory_get_usage(true)valor de retorno que deve ser comparado memory_limit. O exemplo dado na resposta é muito simples, pois não há "memória desperdiçada". O que acontece é que a memória alocada "real" precisa ser aumentada de "1 MiB" para "1,25 MiB" e é isso que aciona o erro fatal . Eu tenho um script de lote complexo com limite de memória de 120 MiB que tem memória alocada "não real" de apenas "80 MiB" quando é cancelado porque a memória alocada "real" atinge o limite.
Martin Prikryl
36

Introdução

Você deve usar memory_get_usage(false)porque o que você quer é a memória usada, não a memória alocada.

Qual é a diferença

Você Google Mailpode ter alocado 25MBespaço de armazenamento para você, mas isso não significa que é o que você está usando no momento.

Isso é exatamente o que o documento PHP estava dizendo

Defina como TRUE para obter o tamanho real da memória alocada do sistema. Se não for definido ou FALSE, apenas a memória usada por emalloc () é relatada.

Ambos os argumentos retornariam memória alocada em relação ao limite de memória, mas a principal diferença é:

memory_get_usage(false)fornece a memória usada por emalloc()while memory_get_usage(true)retorna o marco que pode ser demonstrado aqui Memory Mile Store

Quero saber o quão perto esteve o script de atingir esse limite.

Isso exigiria alguma matemática e só funcionaria em loops ou casos de uso específicos. Por que eu disse isso?

Imagine

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.

Pelo que eu sei, a única maneira de verificar a memória usada para uma variável ou seção específica do PHP é:

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

Consulte a Explicação , mas se você estiver em um loop ou em uma função recursiva, poderá usar o uso máximo de memória para estimar com segurança quando o pico de memória será alcançado.

Exemplo

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
}

Resultado

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

Demonstração ao vivo

Isso ainda pode falhar

Pode falhar porque depois if ($percentage > $peekPoint) { disso ainda adicionar tarefas adicionais com também consome memória

        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.

Conclusão

Não é uma solução perfeita, mas verifique se há memória no intervalo e se ela exceder peek (por exemplo, 90%) exitinstantaneamente e deixe as coisas sofisticadas

Baba
fonte
A memory_limitopção é sobre pilha? ou pilha?
Yousha Aleayoub
E se eu tiver dois scripts em paralelo ou muitos pedidos, a função memory_get_usage () retornar a memória usada para todos os scripts executados ao mesmo tempo ou apenas o script real?
Mohammed Yassine CHABLI
7

real_usagefalse reporta o uso que seu script usou . Este será o mais preciso dos dois.

real_usagetrue relata a memória alocada para seu script. Este será o mais alto dos dois.

Eu provavelmente usaria truese estivesse tentando comparar, já que seu script nunca seria alocado além do limite de memória e continuaria a ser executado enquanto (mais todos os outros scripts) não exceder esse uso.

Glitch Desire
fonte
1
É exatamente o oposto: falseé a memória que o script usou , trueé a memória alocada .
Benjamin
1
@Benjamin Sim, não sei por que entendi tão cegamente errado. Umm, consertado.
Glitch Desire
2

conforme PHP memory_get_usage

real_usage

Defina como TRUE para obter a memória total alocada do sistema, incluindo páginas não utilizadas. Se não for definido ou FALSE, apenas a memória usada é relatada.

então, para obter a memória usada pelo seu script, você deve usar memory_get_usage () já que real_usage é false.

se você deseja obter a memória alocada pelo sistema, mas não se importa com a quantidade realmente usada, use memory_get_usage (true);

Tofeeq
fonte
-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
fonte
1
Bem-vindo ao Stackoverflow! você poderia nos dizer qual é a resposta? Não apenas o código, mas também como você descobriu como corrigir a questão. Obrigado!
Gilles Heinesch de
Embora sua resposta possa fornecer algumas informações potencialmente úteis, não é relevante para a pergunta que está sendo feita. Você pode explicar como sua resposta se relaciona com a pergunta que está sendo feita.
Moritur