2013-04-01 13 views
72

Se l'argomento real_usage è impostato su true, i DOC del PHP dicono che otterranno la dimensione reale della memoria allocata dal sistema. Se è false riceverà la memoria riportata da emalloc()memory_get_peak_usage() con "utilizzo reale"

Quale di queste 2 opzioni restituisce il max. memoria allocata relativa al valore limite di memoria in php.ini?

Voglio sapere quanto vicino è stato il copione a raggiungere quel limite.

+8

Mi piacerebbe indicarti una presentazione di Julien Pauli http://www.youtube.com/watch?v=sm1HUrnsxLI per la conferenza php uk 2013, in cui parla di come la memoria funzioni all'interno di PHP. – mpratt

+0

Vedere anche http://stackoverflow.com/a/7234026/632951 – Pacerier

risposta

96

Ok, consente di testare questo utilizzando un semplice script:

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 
} 

uscita:

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 

Sembra come l'utilizzo reale è la memoria allocata dal sistema - che sembra avere allocato in secchi grandi di quanto attualmente richiesto dalla sceneggiatura. (Immagino per motivi di prestazioni). Questa è anche la memoria utilizzata dal processo php.

L'utilizzo di $real_usage = false è l'utilizzo di memoria effettivamente utilizzato nello script, non la quantità effettiva di memoria allocata dal gestore di memoria di Zend.

Leggi this question per ulteriori informazioni.

In breve: per ottenere quanto sei vicino al limite di memoria, utilizzare $real_usage = true

+2

Il motore Zend alloca la memoria in blocchi da 256K. Il valore di "utilizzo reale" è la somma di tutti questi blocchi. Questo è in realtà il valore utilizzato per attivare l'errore di esaurimento della memoria: 'if (segment_size real_size + segment_size> heap-> limit) { /* Limite di memoria overflow * /'. – cleong

+1

Il valore "non reale" è la somma del numero di byte richiesti dalle chiamate a 'emalloc' (più byte per le intestazioni e l'allineamento della memoria). Non riflette la memoria sprecata a causa di blocchi che non si adattano allo spazio rimanente nei segmenti già assegnati. Se cambi il tuo esempio per allocare (1024 * 256) byte e un limite 2M, la differenza di due diventerà più evidente. – cleong

+0

@Niko, perché hai usato memory_get_peak_usage invece di memory_get_usage? Non dovremmo gc_disable() e usare memory_get_usage per ottenere un risultato più accurato? – Pacerier

6

real_usage false segnalazioni l'utilizzo dello script utilizzato. Questo sarà il più accurato dei due.

real_usage veri rapporti la memoria allocata allo script. Questo sarà il più alto dei due.

Probabilmente userei true se stavo cercando di confrontare, in quanto il tuo script non sarebbe mai stato allocato più del limite di memoria, e continuerebbe a funzionare fintanto che (più tutti gli altri script) non ha superato tale utilizzo .

+4

No, come mostra il mio script, real_usage true è più alto –

+1

È esattamente l'opposto: 'false' è la memoria che lo script * ha usato *,' true' è la memoria * allocata *. – Benjamin

+1

@ Benjamin Sì, non sono sicuro del motivo per cui ho sbagliato così tanto. Umm, risolto. –

29

Introduzione

si dovrebbe usare memory_get_usage(false) perché ciò che si vuole è la memoria utilizzata non è la memoria allocata.

cosa è la differenza

tuo Google Mail potrebbe aver assegnato 25MB di archiviazione per voi, ma non significa che è ciò che avete utilizzato al momento.

Questo è esattamente ciò che il doc PHP stava dicendo

Set this to TRUE to get the real size of memory allocated from system. If not set or FALSE only the memory used by emalloc() is reported.

Sia argomento sarebbe tornato di memoria relativa assegnata al limite di memoria, ma la differenza principale è:

memory_get_usage(false) dare la memoria utilizzata da emalloc() mentre memory_get_usage(true) ritorna pietra miliare che può essere dimostrata qui Memory Mile Store

Voglio sapere quanto era vicina la sceneggiatura per raggiungere quel limite.

Ciò richiederebbe alcuni calcoli e potrebbe funzionare solo in loop o casi d'uso specifici. Perché ho detto tale?

Immaginate

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.

quanto ne so l'unico modo per controllare la memoria utilizzata per una sezione variabile o specifico di PHP è:

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

See Explanation, ma se si è in una funzione loop o ricorsiva si può usare massima l'utilizzo della memoria per stimare in modo sicuro quando verrà raggiunto il picco di memoria.

Esempio

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 
} 

Output

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

Live Demo

Questo può ancora sicuro

Può fallire perché dopo if ($percentage > $peekPoint) { questo ancora ancora aggiungere a che fare compito supplementare con consuma anche la 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.

Conclusione

La sua non è una soluzione perfetta, ma verificare la presenza di memoria a intervalli e se il suo superiore sbirciare (es. 90%) exit all'istante e lasciare le cose fantastiche

1

come da PHP memory_get_usage

real_usage

Set this to TRUE to get total memory allocated from system, including unused pages. If not set or FALSE only the used memory is reported.

in modo da ottenere la memoria utilizzata dallo script si dovrebbe usare memory_get_usage() come real_usage predefinito è false.

se si desidera ottenere la memoria allocata dal sistema ma non importa quanto effettivamente è stato utilizzato, utilizzare memory_get_usage (true);