memory_get_peak_usage () avec "utilisation réelle"

91

Si l' real_usageargument est défini sur truePHP DOCS, dites qu'il obtiendra la taille réelle de la mémoire allouée par le système. Si c'est le cas false, la mémoire sera signalée paremalloc()

Laquelle de ces 2 options renvoie le max. mémoire allouée par rapport à la valeur de limite de mémoire dans php.ini?

Je veux savoir à quel point le script a atteint cette limite.

thelolcat
la source
8
Je voudrais vous renvoyer à une présentation de Julien Pauli youtube.com/watch?v=sm1HUrnsxLI pour la conférence php uk 2013, où il parle du fonctionnement de la mémoire dans PHP.
mpratt

Réponses:

136

Ok, testons cela en utilisant 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
}

Production:

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

On dirait que l'utilisation réelle est la mémoire allouée par le système - qui semble être allouée dans des compartiments plus grands que ce dont le script a actuellement besoin. (Je suppose que pour des raisons de performances). C'est également la mémoire utilisée par le processus php.

L' $real_usage = falseutilisation est l'utilisation de la mémoire que vous avez réellement utilisée dans votre script, pas la quantité réelle de mémoire allouée par le gestionnaire de mémoire de Zend.

Lisez cette question pour plus d'informations.

En bref: pour vous rapprocher de la limite de mémoire, utilisez $real_usage = true

Niko Sams
la source
5
Le moteur Zend alloue de la mémoire par blocs de 256 Ko. La valeur «d'utilisation réelle» est la somme de tous ces morceaux. C'est en fait la valeur utilisée pour déclencher l'erreur d'épuisement de la mémoire: if (segment_size < true_size || heap->real_size + segment_size > heap->limit) { /* Memory limit overflow */.
cleong
2
La valeur "pas réel" est la somme du nombre d'octets requis par les appels à emalloc(plus les octets pour les en-têtes et l'alignement de la mémoire). Il ne reflète pas le gaspillage de mémoire en raison de blocs ne s'insérant pas dans l'espace restant dans les segments déjà alloués. Si vous modifiez votre exemple pour allouer (1024 * 256) octets et une limite de 2M, la différence de deux deviendra plus apparente.
cleong
@Niko, pourquoi avez-vous utilisé memory_get_peak_usage au lieu de memory_get_usage? Ne devrions-nous pas gc_disable () et utiliser memory_get_usage pour obtenir un résultat plus précis?
Pacerier
@Pacerier, la question était de savoir à quel point le script était proche de la limite - car ce pic a du sens, je dirais
Niko Sams
4
Comme @cleong l'a expliqué, cette réponse est en fait erronée, malgré toutes les votes favorables. La memory_get_usage(true)valeur de retour qui devrait être comparé à memory_limit. L'exemple donné dans la réponse est bien trop simple car il n'y a pas de "mémoire" gaspillée. Ce qui se passe, c'est que la "vraie" mémoire allouée doit être augmentée de "1 MiB" à "1,25 MiB" et c'est ce qui déclenche l'erreur fatale J'ai un script batch complexe avec une limite de mémoire de 120 Mio qui ont une mémoire allouée "pas réelle" de seulement "80 Mio" quand elle est abandonnée parce que la mémoire allouée "réelle" atteint la limite.
Martin Prikryl
36

introduction

Vous devriez utiliser memory_get_usage(false)parce que ce que vous voulez, c'est de la mémoire utilisée et non de la mémoire allouée.

Quelle est la différence

Vous avez Google Mailpeut-être alloué 25MBdu stockage pour vous, mais cela ne signifie pas que c'est ce que vous avez utilisé pour le moment.

C'est exactement ce que disait le doc PHP

Définissez ceci sur TRUE pour obtenir la taille réelle de la mémoire allouée par le système. S'il n'est pas défini ou FALSE, seule la mémoire utilisée par emalloc () est signalée.

Les deux arguments renverraient la mémoire allouée par rapport à la limite de mémoire, mais la principale différence est:

memory_get_usage(false)donne la mémoire utilisée par emalloc()while memory_get_usage(true)renvoie le jalon qui peut être démontré ici Memory Mile Store

Je veux savoir à quel point le script a atteint cette limite.

Cela prendrait quelques calculs et pourrait ne fonctionner que dans des boucles ou des cas d'utilisation spécifiques. Pourquoi ai-je dit cela?

Imaginer

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.

Autant que je sache, le seul moyen de vérifier la mémoire utilisée pour une variable ou une section spécifique de PHP est:

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

Voir l'explication , mais si vous êtes dans une boucle ou une fonction récursive, vous pouvez utiliser l'utilisation maximale de la mémoire pour estimer en toute sécurité quand l'aperçu de la mémoire serait atteint.

Exemple

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
}

Production

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

Démo en direct

Cela peut encore échouer

Cela peut échouer car après if ($percentage > $peekPoint) { cela, ajoutez encore à faire une tâche supplémentaire avec consomme également de la mémoire

        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.

Conclusion

Ce n'est pas une solution parfaite, mais vérifiez la mémoire à intervalle et si elle dépasse exitinstantanément (par exemple 90%) et laissez les trucs fantaisistes

Baba
la source
L' memory_limitoption concerne-t-elle le tas? ou pile?
Yousha Aleayoub
que se passe-t-il si j'ai deux scripts en parallèle ou plusieurs requêtes, la fonction memory_get_usage () renvoie la mémoire utilisée pour tous ces scripts exécutés en même temps ou uniquement le script réel?
Mohammed Yassine CHABLI
7

real_usagefalse signale l'utilisation que votre script a utilisée . Ce sera le plus précis des deux.

real_usagetrue rapporte la mémoire allouée à votre script. Ce sera le plus élevé des deux.

J'utiliserais probablement truesi j'essayais de comparer, car votre script ne serait jamais alloué plus que la limite de mémoire et continuerait à fonctionner tant qu'il (ainsi que tous les autres scripts) ne dépasserait pas cette utilisation.

Désir de glitch
la source
1
C'est exactement le contraire: falseest la mémoire utilisée par le script , trueest la mémoire allouée .
Benjamin le
1
@Benjamin Ouais, je ne sais pas pourquoi je me suis trompé si aveuglément. Euh, fixe.
Glitch Desire
2

selon PHP memory_get_usage

real_usage

Définissez ceci sur TRUE pour obtenir la mémoire totale allouée par le système, y compris les pages inutilisées. S'il n'est pas défini ou FALSE, seule la mémoire utilisée est signalée.

donc pour obtenir la mémoire utilisée par votre script, vous devez utiliser memory_get_usage () par défaut, real_usage est false.

si vous souhaitez obtenir la mémoire allouée par le système mais que vous ne vous souciez pas de la quantité réellement utilisée, utilisez memory_get_usage (true);

Tofeeq
la source
-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
la source
1
Bienvenue dans Stackoverflow! pouvez-vous nous dire quelle est la réponse? Pas seulement le code, mais aussi la manière dont vous avez résolu la question. Merci!
Gilles Heinesch
Bien que votre réponse puisse fournir des informations potentiellement utiles, elle n'est pas pertinente pour la question posée. Vous voudrez peut-être expliquer en quoi votre réponse se rapporte à la question posée.
Moritur