Partager via


Exercice 2 - Suivre les allocations de processus en mode utilisateur

Les allocations de tas sont effectuées directement via les API de tas (allocations HeapAlloc, HeapRealloc et C/C++, telles que new, alloc, realloc, calloc) et sont prises en charge à l’aide de trois types de tas :

  1. Tas NT de ligne principale : les demandes d’allocation de services de tailles inférieures à 64 Ko.

  2. Tas à faible fragmentation : composé de sous-segments qui permettent de traiter les demandes d’allocation de blocs de taille fixe.

  3. VirtualAlloc : Services demande d’allocation de tailles supérieures à 64 Ko.

VirtualAlloc est utilisé pour les allocations de mémoire dynamiques volumineuses qui sont effectuées directement via l’API VirtualAlloc . L’utilisation classique est généralement pour les bitmaps ou les mémoires tampons. Vous pouvez utiliser VirtualAlloc pour réserver un bloc de pages, puis effectuer des appels supplémentaires à VirtualAlloc pour valider des pages individuelles à partir du bloc réservé. Cela permet à un processus de réserver une plage de son espace d’adressage virtuel sans consommer de stockage physique jusqu’à ce qu’il soit nécessaire.

Il existe deux concepts à comprendre dans ce domaine :

  1. Mémoire réservée : réserve une plage d’adresses pour l’utilisation, mais n’acquiert pas de ressources de mémoire.

  2. Mémoire validée : garantit que la mémoire physique ou l’espace de fichier de page sera disponible si les adresses sont référencées.

Dans cet exercice, vous allez apprendre à collecter des traces pour examiner comment un processus en mode utilisateur alloue de la mémoire.

L’exercice se concentre sur un processus de test factice appelé MemoryTestApp.exe qui alloue de la mémoire via :

  1. API VirtualAlloc pour valider des mémoires tampons volumineuses.

  2. Nouvel opérateur C ++ pour instancier de petits objets.

Vous pouvez télécharger MemoryTestApp.exeici.

Étape 1 : Collecter une trace virtualAlloc/tas à l’aide de WPR

Les allocations de mémoire volumineuses sont généralement celles qui ont un impact sur l’empreinte d’un processus et sont traitées par l’API VirtualAlloc . C’est là que toutes les investigations doivent commencer, mais il est également possible qu’un processus se comporte mal avec des allocations plus petites (par exemple, des fuites de mémoire à l’aide d’un nouvel opérateur en C++, etc.). Le suivi du tas devient utile lorsque cette situation se produit.

Étape 1.1 : Préparer le système pour le suivi du tas

Le suivi du tas doit être considéré comme facultatif et effectué lorsque l’analyse VirtualAlloc ne fournit aucune explication pertinente d’un problème d’utilisation de la mémoire. Le suivi du tas a tendance à produire des traces plus volumineuses et il est recommandé d’activer le suivi uniquement pour les processus individuels que vous examinez.

Ajouter la clé de Registre pour le processus qui vous intéresse (MemoryTestApp.exe dans ce cas) ; Le suivi du tas est ensuite activé pour chaque création de processus suivante.

reg add "HKLM\Software\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\MemoryTestApp.exe" /v TracingFlags /t REG_DWORD /d 1 /f

Étape 1.2 : Capturer une trace à l’aide de WPR

Dans cette étape, vous allez collecter une trace à l’aide de WPR qui contient des données VirtualAlloc et Heap .

  1. Ouvrez WPR et modifiez la configuration de suivi.

    1. Sélectionnez les fournisseurs VirtualAlloc et Tas .

    2. Sélectionnez Général comme scénario de performances.

    3. Sélectionnez Général comme mode de journalisation.

      Capture d’écran du menu des options de traçage WPR.

  2. Cliquez sur Démarrer pour démarrer le suivi.

  3. Lancez MemoryTestApp.exeet attendez que le processus se termine (cela devrait prendre environ 30 secondes).

  4. Revenez à WPR, enregistrez la trace et ouvrez-la avec Windows Analyseur de performances (WPA).

  5. Ouvrez le menu Trace et sélectionnez Configurer le chemin des symboles.

    • Spécifiez le chemin du cache de symboles. Pour plus d’informations sur les symboles, consultez la page Prise en charge des symboles sur MSDN.
  6. Ouvrez le menu Trace et sélectionnez Charger des symboles.

Vous disposez maintenant d’une trace qui contient tous les modèles d’allocation de mémoire pour le processus MemoryTestApp.exe pendant sa durée de vie.

Étape 2 : Passer en revue les allocations dynamiques VirtualAlloc

Les données VirtualAlloc détaillées sont exposées via le graphique « Durées de vie de validation VirtualAlloc » dans WPA. Les principales colonnes d’intérêt sont les suivantes :

Colonne Description
Processus

Nom du processus qui effectue des allocations de mémoire via VirtualAlloc.

Pile de validations

Pile d’appels qui montre le chemin du code menant à l’allocation de mémoire.

Heure de validation

Horodatage du moment où la mémoire a été allouée.

Temps de dégagement

Horodatage du moment où la mémoire a été libérée.

Impact sur la taille

Taille des allocations en attente ou différence de taille entre le début et la fin de l’intervalle de temps sélectionné. Cette taille s’ajuste en fonction du port d’affichage sélectionné.

La valeur Impacting Size est égale à zéro si toute la mémoire allouée par un processus est libérée à la fin de l’intervalle visualisant dans WPA.

Taille

Somme cumulée de toutes les allocations pendant l’intervalle de temps sélectionné.

Suivez ces étapes pour analyser MemoryTestApp.exe

  1. Recherchez le graphique Durées de vie de validation VirtualAlloc dans la catégorie Mémoire du Explorer Graph.

  2. Faites glisser et déposez les durées de vie de validation VirtualAlloc sous l’onglet Analyse .

  3. Organisez la table pour afficher ces colonnes. Cliquez avec le bouton droit sur les en-têtes de colonne pour ajouter ou supprimer des colonnes.

    1. Processus

    2. Impact sur le type

    3. Pile de validations

    4. Commit Time et Decommit Time

    5. Count

    6. Impact sur la taille et la taille

  4. Recherchez MemoryTestApp.exe dans la liste des processus.

  5. Appliquez un filtre pour conserver uniquement MemoryTestApp.exe sur le graphique.

    • Cliquez avec le bouton droit, puis sélectionnez Filtrer dans la sélection.

Capture d’écran montrant comment filtrer les résultats.

Votre fenêtre d’affichage d’analyse doit ressembler à ceci :

Exemple de graphique de ce à quoi les données ressembleraient lorsqu’elles sont filtrées.

Dans l’exemple précédent, deux valeurs sont intéressantes :

  • Taille de 126 Mo : cela indique que MemoryTestApp.exe alloué un total de 125 Mo au cours de sa durée de vie. Il représente la somme cumulée de tous les appels d’API VirtualAlloc effectués par le processus et ses dépendances.

  • Impact sur la taille de 0 Mo : cela indique que toute la mémoire allouée par le processus est libérée à la fin de l’intervalle de temps en cours d’analyse. Le système n’a pas souffert d’une augmentation de son utilisation de la mémoire à l’état stable.

Étape 2.1 : Analyser l’utilisation de la mémoire à l’état stable

Lorsque vous examinez l’allocation de mémoire, vous devez essayer de répondre à la question suivante : « Pourquoi l’utilisation de la mémoire à l’état stable augmente-t-elle dans ce scénario ? » Dans l’exemple MemoryTestApp.exe , vous pouvez voir qu’il dispose d’environ 10 Mo de mémoire à l’état stable alloué au début, puis qu’il augmente à 20 Mo à mi-chemin.

Capture d’écran des exemples de données montrant l’utilisation de la mémoire.

Pour examiner ce comportement, réduisez le zoom à environ l’intervalle de temps lorsque l’augmentation soudaine se produit au milieu de la trace.

Capture d’écran montrant comment zoomer sur les données.

Votre fenêtre d’affichage doit ressembler à ceci.

Capture d’écran des exemples de données après l’application de l’option de zoom shpwing graph avec VirtualAlloc Commit LifeTimes et Commit by Process

Comme vous pouvez le voir, la taille impactante est maintenant de 10 Mo. Cela signifie que, entre le début et la fin de l’intervalle de temps analysé, l’utilisation de la mémoire à l’état stable augmente de 10 Mo.

  1. Triez en impactant la taille en cliquant sur l’en-tête de colonne.

  2. Développez la ligneMemoryTestApp.exe (dans la colonne Processus ).

  3. Développez la ligne Impacting (dans la colonne Type d’impact ).

  4. Parcourez le processus Commit Stack jusqu’à trouver la fonction qui a alloué 10 Mo de mémoire.

    Capture d’écran de l’exemple de table de données montrant le numéro de ligne, le processus, le type d’impact, la pile de validation, l’heure de validation, le temps de dégagement, le nombre et la taille d’impact

Dans cet exemple, la fonction Main de MemoryTestApp.exe alloue 10 Mo de mémoire au milieu de la charge de travail en appelant directement VirtualAlloc. Dans le monde réel, le développeur d’applications doit déterminer si l’allocation est raisonnable ou si le code peut être réorganisé pour réduire l’augmentation de l’utilisation de la mémoire à l’état stable.

Vous pouvez maintenant annuler la fenêtre d’affichage dans WPA.

Screenhsot of unzoom menu.

Étape 2.2 : Analyser l’utilisation temporaire (ou maximale) de la mémoire

Lorsque vous examinez les allocations de mémoire, vous devez essayer de répondre à la question suivante : « Pourquoi y a-t-il un pic temporaire dans l’utilisation de la mémoire pour cette partie du scénario ? » Les allocations temporaires provoquent des pics d’utilisation de la mémoire et peuvent entraîner une fragmentation et pousser du contenu précieux hors du cache de secours système en cas de pression de la mémoire.

Dans l’exemple MemoryTest , vous pouvez voir qu’il existe 10 pics différents d’utilisation de la mémoire (de 10 Mo) répartis uniformément dans la trace.

Capture d’écran du graphique montrant les données d’utilisation de la mémoire.

Réduisez le zoom sur les quatre derniers pics, pour vous concentrer sur une plus petite zone d’intérêt et réduire le bruit des comportements non pertinents.

Capture d’écran de l’option de zoom.

Votre fenêtre d’affichage doit ressembler à ceci :

Capture d’écran du graphique montrant les données d’utilisation de la mémoire à l’aide de l’option zoom.

  1. Triez par Taille en cliquant sur l’en-tête de colonne.

  2. Développez la ligneMemoryTestApp.exe (dans la colonne Processus ).

  3. Cliquez sur la ligne Temporaire (dans la colonne Type impactant ).

    • Cela doit mettre en évidence en bleu tous les pics d’utilisation de la mémoire dans la fenêtre d’affichage.
  4. Notez la valeur des différentes colonnes :

    1. Nombre = 4 : cela indique que quatre allocations de mémoire temporaires ont été effectuées pendant cet intervalle de temps.

    2. Impact sur la taille = 0 Mo : cela indique que les quatre allocations de mémoire temporaires ont été libérées à la fin de l’intervalle de temps.

    3. Taille = 40 Mo : cela indique que la somme des quatre allocations de mémoire temporaires s’élève à 40 Mo de mémoire.

  5. Parcourez la pile de validation du processus jusqu’à ce que vous trouviez les fonctions qui ont alloué 40 Mo de mémoire.

    Capture d’écran des données d’utilisation de la mémoire.

Dans cet exemple, la fonction Main de MemoryTestApp.exe appelle une fonction nommée Operation1, qui à son tour appelle une fonction nommée ManipulateTemporaryBuffer. Cette fonction ManipulateTemporaryBuffer appelle ensuite directement VirtualAlloc quatre fois, créant et libérant une mémoire tampon de 10 Mo à chaque fois. Les mémoires tampons ne durent que 100 ms chacune. L’allocation des mémoires tampons et les temps libres sont représentés par les colonnes Temps de validation et Temps de validation .

Dans le monde réel, le développeur d’applications détermine si ces allocations temporaires de mémoire tampon temporaires de courte durée sont nécessaires, ou si elles peuvent être remplacées par une mémoire tampon permanente pour l’opération.

Vous pouvez maintenant annuler la fenêtre d’affichage dans WPA.

Étape 3 : Passer en revue les allocations dynamiques de tas

Jusqu’à présent, l’analyse s’est concentrée uniquement sur les allocations de mémoire volumineuses qui sont effectuées par l’API VirtualAlloc . L’étape suivante consiste à déterminer s’il existe des problèmes avec d’autres petites allocations effectuées par le processus, en utilisant les données de tas initialement collectées.

Les données détaillées du tas sont exposées via le graphique « Allocations de tas » dans WPA. Les colonnes clés qui vous intéressent sont les suivantes :

Colonne Description
Processus Nom du processus qui effectue l’allocation de mémoire.
Handle

Identificateur du tas utilisé pour traiter l’allocation.

Les tas peuvent être créés, de sorte qu’il peut y avoir plusieurs handles de tas pour le processus.

Pile Pile des appels qui montre le chemin du code qui conduit à l’allocation de mémoire.
Alloc Time Horodatage de l’allocation de mémoire.
Impact sur la taille Taille des allocations en attente ou différence entre le début et la fin de la fenêtre d’affichage sélectionnée. Cette taille s’ajuste en fonction de l’intervalle de temps sélectionné.
Taille Somme cumulée de toutes les allocations/désallocations.

Suivez ces étapes pour analyser MemoryTestApp.exe

  1. Recherchez le graphique Allocations de tas dans la catégorie Mémoire de l’Explorer Graph.

  2. Faites glisser et déposez les allocations de tas dans l’onglet Analyse .

  3. Organisez la table pour afficher ces colonnes :

    1. Processus

    2. Handle

    3. Type impactant

    4. Pile

    5. AllocTime

    6. Count

    7. Impact sur la taille et lataille

  4. RecherchezMemoryTestApp.exe dans la liste des processus.

  5. Appliquez un filtre pour conserver uniquement MemoryTestApp.exe sur le graphique.

    • Cliquez avec le bouton droit et sélectionnez Filtrer sur sélection.

Votre fenêtre d’affichage doit ressembler à ceci :

Capture d’écran d’exemples de données montrant le graphique Allocations de tas de taille exceptionnelle par processus et handle

Dans cet exemple, vous pouvez voir que l’un des tas augmente régulièrement en taille au fil du temps à un rythme constant. Il y a 1 200 allocations de mémoire sur ce tas, ce qui correspond à 130 Ko de mémoire utilisée à la fin de l’intervalle.

  1. Effectuez un zoom avant sur un intervalle plus petit (par exemple, 10 secondes) au milieu de la trace.

  2. Développez le handle principal qui affiche la plus grande quantité d’allocations (comme indiqué dans la colonne Impacting Size ).

  3. Développez le type Impacting .

  4. Parcourez la pile de processus jusqu’à ce que vous trouviez la fonction responsable de l’allocation de toute cette mémoire.

    Capture d’écran de l’exemple de table de données montrant Process, Handle, Impacting Type, Stack, AllocTime, Count, Impacting Size et Size avec deux lignes sélectionnées

Dans cet exemple, la fonction Main de MemoryTestApp.exe appelle une fonction nommée InnerLoopOperation. Cette fonction InnerLoopOperation alloue ensuite 40 octets de mémoire 319 fois via le nouvel opérateur C++. Cette mémoire reste allouée jusqu’à l’arrêt du processus.

Dans le monde réel, le développeur d’applications doit ensuite déterminer si ce comportement implique une fuite de mémoire possible et résoudre le problème.

Étape 4 : Nettoyer le système de test

Une fois l’analyse terminée, vous devez propre le Registre pour vous assurer que le suivi du tas est désactivé pour le processus. Exécutez cette commande sur une invite de commandes avec élévation de privilèges :

reg delete "HKLM\Software\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\MemoryTestApp.exe" /v TracingFlags /f