web-dev-qa-db-fra.com

Comment déterminer l'empreinte mémoire (taille) d'une variable?

Existe-t-il une fonction dans PHP (ou une extension PHP) pour connaître la quantité de mémoire utilisée par une variable donnée? sizeof me dit juste le nombre d'éléments/propriétés.

memory_get_usage aide en ce sens qu'il me donne la taille de la mémoire utilisée par le script whole . Y a-t-il un moyen de faire cela pour une seule variable?

Notez qu'il s'agit d'une machine de développement. Il est donc possible de charger des extensions ou des outils de débogage.

96
Piskvor

Vous avez probablement besoin d'un correcteur de mémoire. J'ai recueilli des informations à partir de SO mais j'ai copié un élément important qui peut également vous aider.

Comme vous le savez probablement, Xdebug a abandonné la prise en charge du profilage de la mémoire depuis la version 2. *. Veuillez rechercher la chaîne "fonctions supprimées" ici: http://www.xdebug.org/updates.php

Fonctions supprimées

Suppression de la prise en charge du profilage de la mémoire car cela ne fonctionnait pas correctement.

Autres options du profileur

php-memory-profiler

https://github.com/arnaud-lb/php-memory-profiler . Voici ce que j'ai fait sur mon serveur Ubuntu pour l'activer:

Sudo apt-get install libjudy-dev libjudydebian1
Sudo pecl install memprof
echo "extension=memprof.so" > /etc/php5/mods-available/memprof.ini
Sudo php5enmod memprof
service Apache2 restart

Et puis dans mon code:

<?php
memprof_enable();
// do your stuff
memprof_dump_callgrind(fopen("/tmp/callgrind.out", "w"));

Enfin, ouvrez le fichier callgrind.out avec KCachegrind

Utiliser Google gperftools (recommandé!)

Tout d’abord, installez Google gperftools en téléchargeant le dernier package ici: https://code.google.com/p/gperftools/

Alors comme toujours:

Sudo apt-get update
Sudo apt-get install libunwind-dev -y
./configure
make
make install

Maintenant dans votre code:

memprof_enable();

// do your magic

memprof_dump_pprof(fopen("/tmp/profile.heap", "w"));

Ouvrez ensuite votre terminal et lancez:

pprof --web /tmp/profile.heap

(pprof} _ va créer une nouvelle fenêtre dans votre session de navigateur existante avec quelque chose comme ce qui suit:

PHP memory profiling with memprof and gperftools

Xhprof + Xhgui (le meilleur à mon avis pour décrire le processeur et la mémoire)

Avec Xhprof et Xhgui, vous pouvez également définir l'utilisation de l'unité centrale de traitement ou simplement l'utilisation de la mémoire, si c'est votre problème pour le moment . peut être écrit à la fois sur mongo ou dans le système de fichiers.

Pour plus de détails voir ici .

Blackfire

Blackfire est un profileur PHP de SensioLabs, les gars de Symfony2 https://blackfire.io/

Si vous utilisez puphpet pour configurer votre machine virtuelle, vous serez heureux de savoir qu’elle est prise en charge ;-)

Xdebug et suivi de l'utilisation de la mémoire

XDEBUG2 est une extension pour PHP. Xdebug vous permet de consigner tous les appels de fonction, y compris les paramètres et les valeurs renvoyées dans un fichier de formats différents. Il existe trois formats de sortie. L'un est conçu comme une trace lisible par l'homme, un autre est plus adapté aux programmes informatiques car il est plus facile à analyser, et le dernier utilise HTML pour formater la trace. Vous pouvez basculer entre les deux formats différents avec le réglage. Un exemple serait disponible ici

pour P

forp simple, non intrusif, orienté production, profileur PHP. Certaines des fonctionnalités sont:

  • mesure du temps et mémoire allouée pour chaque fonction

  • L'utilisation du processeur

  • numéro de fichier et de ligne de l'appel de fonction

  • sortie au format d'événement Trace de Google

  • légende des fonctions

  • regroupement de fonctions

  • alias de fonctions (utile pour les fonctions anonymes)

DBG

DBG est un débogueur php complet, un outil interactif qui vous aide à déboguer des scripts php. Il fonctionne sur un serveur Web de production et/ou de développement et vous permet de déboguer vos scripts localement ou à distance, à partir d'un IDE ou d'une console. Ses fonctionnalités sont les suivantes:

  • Débogage local et à distance

  • Activation explicite et implicite

  • Pile d'appels, y compris les appels de fonction, les appels de méthode dynamiques et statiques, avec leurs paramètres

  • Navigation dans la pile d'appels avec possibilité d'évaluer des variables aux endroits correspondants (imbriqués)

  • Fonctionnalités Pas à pas/Pas à pas/Pas à pas/Courir au curseur

  • Points d'arrêt conditionnels

  • Points d'arrêt globaux

  • Journalisation des erreurs et des avertissements

  • Plusieurs sessions simultanées pour le débogage parallèle

  • Prise en charge des interfaces graphiques et des interfaces de ligne de commande

  • Réseaux IPv6 et IPv4 pris en charge

  • Toutes les données transférées par le débogueur peuvent éventuellement être protégées avec SSL

40
Vineet1982

Il n'y a pas de moyen direct d'obtenir l'utilisation de la mémoire d'une seule variable, mais comme Gordon l'a suggéré, vous pouvez utiliser memory_get_usage. Cela renvoie la quantité totale de mémoire allouée. Vous pouvez donc utiliser une solution de contournement et mesurer l'utilisation avant et après pour obtenir l'utilisation d'une seule variable. C'est un peu hacky, mais ça devrait marcher.

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

Notez que ceci n’est en aucun cas une méthode fiable, vous ne pouvez pas être sûr que rien d’autre ne touche à la mémoire lors de l’affectation de la variable, elle ne doit donc être utilisée qu’à titre approximatif.

Vous pouvez réellement transformer cela en fonction en créant une copie de la variable à l'intérieur de la fonction et en mesurant la mémoire utilisée. Je n'ai pas testé cela, mais en principe, je ne vois rien de mal à cela:

function sizeofvar($var) {
    $start_memory = memory_get_usage();
    $tmp = unserialize(serialize($var));
    return memory_get_usage() - $start_memory;
}
91
Tatu Ulmanen

Non, il n'y en a pas. Mais vous pouvez serialize($var) et vérifiez la strlen du résultat pour une approximation.

22
Aistina

En réponse à la réponse de Tatu Ulmanens:

Il convient de noter que $start_memory utilisera lui-même de la mémoire (PHP_INT_SIZE * 8).

Donc, toute la fonction devrait devenir:

function sizeofvar($var) {
    $start_memory = memory_get_usage();
    $var = unserialize(serialize($var));
    return memory_get_usage() - $start_memory - PHP_INT_SIZE * 8;
}

Désolé d'ajouter ceci comme réponse supplémentaire, mais je ne peux pas encore commenter une réponse.

Mise à jour: le * 8 n'est pas définitif. Cela peut dépendre apparemment de la version php et éventuellement de 64/32 bits. 

20
para

Voir:

Notez que cela ne vous donnera cependant pas l'utilisation de la mémoire d'une variable spécifique. Mais vous pouvez passer des appels à ces fonctions avant et après l’affectation de la variable, puis comparer les valeurs. Cela devrait vous donner une idée de la mémoire utilisée.

Vous pouvez également jeter un œil à l’extension PECL Memtrack , bien que la documentation soit un peu absente, voire inexistante.

4
Gordon

Vous pouvez choisir de calculer la différence de mémoire sur une valeur de retour de rappel. C'est une solution plus élégante disponible dans PHP 5.3+.

function calculateFootprint($callback) {
    $startMemory = memory_get_usage();
    $result = call_user_func($callback);
    return memory_get_usage() - $startMemory;
}

$memoryFootprint = calculateFootprint(
    function() {
        return range(1, 1000000);
    }
);

echo ($memoryFootprint / (1024 * 1024)) . ' MB' . PHP_EOL;
3
Liviu Bundă

Vous ne pouvez pas calculer rétrospectivement l'empreinte exacte d'une variable car deux variables peuvent partager le même espace alloué dans la mémoire

Essayons de partager la mémoire entre deux tableaux, on voit que l’allocation du deuxième tableau coûte la moitié de la mémoire du premier. Lorsque nous désactivons le premier, presque toute la mémoire est encore utilisée par le second.

echo memory_get_usage()."\n"; // <-- 433200
$c=range(1,100);
echo memory_get_usage()."\n"; // <-- 444348 (+11148)
$d=array_slice($c, 1);
echo memory_get_usage()."\n"; // <-- 451040 (+6692)
unset($c);
echo memory_get_usage()."\n"; // <-- 444232 (-6808)
unset($d);
echo memory_get_usage()."\n"; // <-- 433200 (-11032)

Nous ne pouvons donc pas conclure que le second tableau utilise la moitié de la mémoire, car il devient faux lorsque nous désactivons le premier.

Pour avoir une vue complète de la façon dont la mémoire est allouée dans PHP et pour quel usage, je vous suggère de lire l'article suivant: Quelle est la taille des tableaux (et des valeurs) de PHP? (Indice: GRAND!)

La base de données Comptage de références dans la documentation PHP contient également de nombreuses informations sur l'utilisation de la mémoire et le nombre de références compte pour un segment de données partagé.

Les différentes solutions présentées ici conviennent bien aux approximations, mais aucune ne peut gérer la gestion subtile de la mémoire PHP.

  1. calcul de l'espace nouvellement alloué

Si vous voulez le nouvel espace alloué après une affectation, vous devez utiliser memory_get_usage() avant et après l'allocation, car son utilisation avec une copie vous donne une vision erronée de la réalité.

// open output buffer
echo "Result: ";
// call every function once
range(1,1); memory_get_usage();

echo memory_get_usage()."\n";
$c=range(1,100);
echo memory_get_usage()."\n";

N'oubliez pas que si vous souhaitez stocker le résultat de la première memory_get_usage(), la variable doit déjà exister avant et memory_get_usage() doit être appelée une autre fois, ainsi que toutes les autres fonctions.

Si vous souhaitez utiliser l'écho comme dans l'exemple ci-dessus, votre tampon de sortie doit déjà être ouvert pour éviter que la mémoire de comptabilité ne soit nécessaire pour ouvrir le tampon de sortie.

  1. calcul de l'espace requis

Si vous souhaitez utiliser une fonction pour calculer l'espace requis pour stocker une copie d'une variable, le code suivant prend en charge différentes optimisations:

<?php
function getMemorySize($value) {
    // existing variable with integer value so that the next line
    // does not add memory consumption when initiating $start variable
    $start=1;
    $start=memory_get_usage();
    // json functions return less bytes consumptions than serialize
    $tmp=json_decode(json_encode($value));
    return memory_get_usage() - $start;
}

// open the output buffer, and calls the function one first time
echo ".\n";
getMemorySize(NULL);

// test inside a function in order to not care about memory used
// by the addition of the variable name to the $_GLOBAL array
function test() {
    // call the function name once 
    range(1,1);

    // we will compare the two values (see comment above about initialization of $start)
    $start=1;
    $start=memory_get_usage();
    $c=range(1,100);
    echo memory_get_usage()-$start."\n";
    echo getMemorySize($c)."\n";
}
test();

// same result, this works fine.
// 11044
// 11044

Notez que la taille du nom de la variable est importante dans la mémoire allouée.

  1. Vérifiez votre code !!

Une variable a une taille de base définie par la structure C interne utilisée dans le code source PHP. Cette taille ne fluctue pas dans le cas des nombres. Pour les chaînes, cela ajouterait la longueur de la chaîne.

typedef union _zvalue_value {
    long lval;                  /* long value */
    double dval;                /* double value */
    struct {
        char *val;
        int len;
    } str;
    HashTable *ht;              /* hash table value */
    zend_object_value obj;
} zvalue_value;

Si nous ne prenons pas en compte l'initialisation du nom de la variable, nous savons déjà combien de fois une variable utilise (dans le cas de nombres et de chaînes):

44 octets dans le cas de nombres

+ 24 octets dans le cas de chaînes

+ la longueur de la chaîne (y compris le dernier caractère NUL)

(ces nombres peuvent changer en fonction de la version PHP))

Vous devez arrondir à un multiple de 4 octets en raison de l'alignement de la mémoire. Si la variable se trouve dans l'espace global (pas dans une fonction), elle allouera également 64 octets supplémentaires.

Donc, si vous souhaitez utiliser l'un des codes de cette page, vous devez vérifier que le résultat obtenu à l'aide de simples cas de test (chaînes ou nombres) correspond à ces données en tenant compte de chacune des indications de ce message (tableau $ _GLOBAL, premier appel de fonction, tampon de sortie, ...)

3
Adam

J'ai eu un problème similaire, et la solution que j'ai utilisée était d'écrire la variable dans un fichier, puis d'exécuter la commande filesize (). À peu près comme ça (code non testé):

function getVariableSize ( $foo ) 
{
    $tmpfile = "temp-" . microtime(true) . ".txt";
    file_put_contents($tmpfile, $foo);
    $size = filesize($tmpfile);
    unlink($tmpfile);
    return $size;
}

Cette solution n'est pas très rapide car elle implique des entrées/sorties sur disque, mais elle devrait vous donner quelque chose de beaucoup plus précis que les astuces memory_get_usage. Cela dépend de la précision dont vous avez besoin.

2
Alan Bellows
function mesure($var){
    $start = memory_get_usage();
    if(is_string($var)){
        $newValue = $var . '';
    }elseif(is_numeric($var)){
        $newValue = $var + 0;
    }elseif(is_object($var)){
        $newValue = clone $var;
    }elseif(is_array($var)){
        $newValue = array_flip($var, []);
    }
    return memory_get_usage() - $start;
}
1
Abdelilah

Jamais essayé, mais des traces de Xdebug avec xdebug.collect_assignment s peuvent suffire.

1
Arkh

Le script suivant montre l'utilisation totale de la mémoire d'une seule variable.

function getVariableUsage($var) {
  $total_memory = memory_get_usage();
  $tmp = unserialize(serialize($var));
  return memory_get_usage() - $total_memory; 
}

$var = "Hey, what's you doing?";
echo getVariableUsage($var);

Regarde ça

http://www.phpzag.com/how-much-memory-do-php-variables-use/

0
vongani masanganye