web-dev-qa-db-fra.com

Suivi de l'utilisation de la mémoire dans PHP

J'essaie de suivre l'utilisation de la mémoire d'un script qui traite les URL. L'idée de base est de vérifier qu'il existe un tampon raisonnable avant d'ajouter une autre URL à un multi-gestionnaire cURL. J'utilise un concept de "roulement cURL" qui traite les données d'une URL pendant l'exécution du multi-gestionnaire. Cela signifie que je peux garder N connexions actives en ajoutant une nouvelle URL à partir d'un pool chaque fois qu'une URL existante est traitée et supprimée.

J'ai utilisé memory_get_usage() avec des résultats positifs. L'ajout de l'indicateur real_usage A aidé (pas vraiment clair sur la différence entre la mémoire "système" et la mémoire "emalloc", mais le système affiche des nombres plus importants). memory_get_usage() augmente au fur et à mesure que les URL sont ajoutées puis diminue lorsque l'ensemble d'URL est épuisé. Cependant, je viens de dépasser la limite de 32M avec ma dernière vérification de la mémoire étant ~ 18M.

J'interroge l'utilisation de la mémoire chaque fois que cURL multi-signaux renvoie une demande. Étant donné que plusieurs demandes peuvent retourner en même temps, il est possible qu'un groupe d'URL renvoie des données en même temps et dépasse en fait l'utilisation de la mémoire de 14M. Cependant, si memory_get_usage() est précis, je suppose que c'est ce qui se passe.

[Mise à jour: J'aurais dû exécuter plus de tests avant de demander, je suppose, la limite de mémoire de php a augmenté (mais a laissé la quantité "sûre" la même dans le script) et l'utilisation de la mémoire telle que rapportée est passée de dessous moi-même limite imposée de 25M à plus de 32M. Puis, comme prévu, la vitesse de descente s'est lentement ralentie, car les URL n'ont pas été ajoutées. Mais je vais laisser la question en suspens: est-ce la bonne façon de procéder?]

Puis-je faire confiance à memory_get_usage() de cette manière? Existe-t-il de meilleures méthodes alternatives pour obtenir l'utilisation de la mémoire (j'ai vu certains scripts analyser la sortie des commandes Shell)?

32
Tim Lytle

real_usage Fonctionne de cette façon:

Le gestionnaire de mémoire de Zend n'utilise pas le système malloc pour chaque bloc dont il a besoin. Au lieu de cela, il alloue un gros bloc de mémoire système (par incréments de 256 Ko, peut être modifié en définissant la variable d'environnement ZEND_MM_SEG_SIZE) Et le gère en interne. Il existe donc deux types d'utilisation de la mémoire:

  1. La quantité de mémoire prise par le moteur sur le système d'exploitation ("utilisation réelle")
  2. Quelle quantité de cette mémoire a été réellement utilisée par l'application ("utilisation interne")

L'un ou l'autre peut être retourné par memory_get_usage(). Lequel vous est le plus utile dépend de ce que vous cherchez. Si vous cherchez à optimiser votre code dans des parties spécifiques, "interne" pourrait être plus utile pour vous. Si vous suivez l'utilisation de la mémoire à l'échelle mondiale, "réel" serait plus utile. memory_limit Limite le nombre "réel", donc dès que tous les blocs autorisés par la limite sont extraits du système et que le gestionnaire de mémoire ne peut pas allouer un bloc demandé, l'allocation échoue. Notez que l'utilisation "interne" dans ce cas peut être inférieure à la limite, mais l'allocation peut toujours échouer en raison de la fragmentation.

De plus, si vous utilisez un outil de suivi de mémoire externe, vous pouvez définir cette variable d'environnement USE_ZEND_ALLOC=0 Qui désactiverait le mécanisme ci-dessus et obligerait le moteur à toujours utiliser malloc(). Cela aurait des performances bien pires mais vous permet d'utiliser des outils de suivi de malloc.

Voir aussi n article sur ce gestionnaire de mémoire , il contient aussi quelques exemples de code.

45
StasM

Je suppose également que memory_get_usage() est sûr mais je suppose que vous pouvez comparer les deux méthodes et décider par vous-même, voici une fonction qui analyse les appels système:

function Memory_Usage($decimals = 2)
{
    $result = 0;

    if (function_exists('memory_get_usage'))
    {
        $result = memory_get_usage() / 1024;
    }

    else
    {
        if (function_exists('exec'))
        {
            $output = array();

            if (substr(strtoupper(PHP_OS), 0, 3) == 'WIN')
            {
                exec('tasklist /FI "PID eq ' . getmypid() . '" /FO LIST', $output);

                $result = preg_replace('/[\D]/', '', $output[5]);
            }

            else
            {
                exec('ps -eo%mem,rss,pid | grep ' . getmypid(), $output);

                $output = explode('  ', $output[0]);

                $result = $output[1];
            }
        }
    }

    return number_format(intval($result) / 1024, $decimals, '.', '');
}
8
Alix Axel

Utilisez xdebug , car il a été récemment mis à jour (le 29 janvier) pour inclure désormais les informations de profilage de la mémoire. Il garde une trace des appels de fonction et de la quantité de mémoire qu'ils consomment. Cela vous permet d'obtenir une vue très perspicace de votre code et, à tout le moins, de vous orienter vers la prise de conscience des problèmes.

La documentation est utile, mais essentiellement vous, installez-la, activez le profilage xdebug.profiler_enable = 1 et donnez la sortie xdebug.profiler_output_dir=/some/path à un outil tel que qcachegrind pour faire le gros du travail, en le voyant visuellement.

1
SeanDowney