Que sont les octets privés, les octets virtuels, le jeu de travail?


491

J'essaie d'utiliser l'utilitaire perfmon windows pour déboguer les fuites de mémoire dans un processus.

Voici comment perfmon explique les termes:

L'ensemble de travail est la taille actuelle, en octets, de l'ensemble de travail de ce processus. Le Working Set est l'ensemble des pages mémoire touchées récemment par les threads du processus. Si la mémoire disponible sur l'ordinateur dépasse un seuil, les pages restent dans le jeu de travail d'un processus même si elles ne sont pas utilisées. Lorsque la mémoire disponible tombe en dessous d'un seuil, les pages sont supprimées des ensembles de travail. S'ils sont nécessaires, ils seront ensuite réinstallés dans le groupe de travail avant de quitter la mémoire principale.

Octets virtuels est la taille actuelle, en octets, de l'espace d'adressage virtuel utilisé par le processus. L'utilisation de l'espace d'adressage virtuel n'implique pas nécessairement l'utilisation correspondante du disque ou des pages de mémoire principale. L'espace virtuel est limité et le processus peut limiter sa capacité à charger des bibliothèques.

Octets privés est la taille actuelle, en octets, de la mémoire que ce processus a alloué qui ne peut pas être partagé avec d' autres processus.

Ce sont les questions que j'ai:

Est-ce les octets privés que je devrais mesurer pour être sûr que le processus présente des fuites, car il n'implique aucune bibliothèque partagée et, le cas échéant, des fuites proviendront du processus lui-même?

Quelle est la mémoire totale consommée par le processus? S'agit-il des octets virtuels ou est-ce la somme des octets virtuels et de l'ensemble de travail?

Existe-t-il une relation entre les octets privés, l'ensemble de travail et les octets virtuels?

Existe-t-il d'autres outils qui donnent une meilleure idée de l'utilisation de la mémoire?


3
Un meilleur outil serait valgrind / helgrind, mais pas sous Windows malheureusement :(
Kornel Kisielewicz

Est-ce l'octet privé que je devrais mesurer pour être sûr si le processus a une fuite? Si les octets privés d'un processus ne se développent pas, vous n'avez aucune fuite de mémoire. S'ils grandissent, cela peut être dû à des fuites de mémoire et à la fragmentation de la mémoire. Je pense qu'il est difficile de dire en regardant la croissance des octets privés ce que cela signifie exactement.

@SergeiKurenkov Une chose que nous pouvons dire, c'est que cela ne serait JAMAIS dû à une "fragmentation de la mémoire".
Jamie Hanrahan

Réponses:


517

La réponse courte à cette question est qu'aucune de ces valeurs n'est un indicateur fiable de la quantité de mémoire qu'un exécutable utilise réellement, et aucune d'entre elles n'est vraiment appropriée pour déboguer une fuite de mémoire.

Les octets privés font référence à la quantité de mémoire que l'exécutable du processus a demandée - pas nécessairement la quantité qu'il utilise réellement . Ils sont "privés" car ils excluent (généralement) les fichiers mappés en mémoire (c'est-à-dire les DLL partagées). Mais - voici le hic - ils n'excluent pas nécessairement la mémoire allouée par ces fichiers . Il n'y a aucun moyen de savoir si un changement d'octets privés était dû à l'exécutable lui-même ou à une bibliothèque liée. Les octets privés ne sont pas non plus exclusivement de la mémoire physique; ils peuvent être paginés sur disque ou dans la liste des pages de secours (c'est-à-dire qu'ils ne sont plus utilisés, mais pas encore paginés non plus).

L'ensemble de travail fait référence à la mémoire physique totale (RAM) utilisée par le processus. Cependant, contrairement aux octets privés, cela inclut également les fichiers mappés en mémoire et diverses autres ressources, c'est donc une mesure encore moins précise que les octets privés. Il s'agit de la même valeur qui est signalée dans «Mem Usage» du Gestionnaire des tâches et a été la source de quantités infinies de confusion ces dernières années. La mémoire dans l'ensemble de travail est "physique" dans le sens où elle peut être adressée sans défaut de page; cependant, la liste des pages en attente est également physiquement en mémoire mais n'est pas signalée dans le jeu de travail, et c'est pourquoi vous pouvez voir «l'utilisation de Mem» tomber soudainement lorsque vous réduisez une application.

Les octets virtuels sont l' espace d'adressage virtuel total occupé par l'ensemble du processus. C'est comme l'ensemble de travail, dans le sens où il inclut des fichiers mappés en mémoire (DLL partagées), mais il inclut également des données dans la liste de secours et des données qui ont déjà été paginées et qui se trouvent quelque part dans un fichier d'échange sur le disque. Le nombre total d'octets virtuels utilisés par chaque processus sur un système soumis à une charge élevée ajoutera beaucoup plus de mémoire que la machine n'en a réellement.

Les relations sont donc:

  • Les octets privés sont ce que votre application a réellement alloué, mais incluent l'utilisation du fichier d'échange;
  • L'ensemble de travail correspond aux octets privés non paginés et aux fichiers mappés en mémoire;
  • Les octets virtuels sont l'ensemble de travail plus les octets privés paginés et la liste de secours.

Il y a un autre problème ici; tout comme les bibliothèques partagées peuvent allouer de la mémoire à l'intérieur de votre module d'application, conduisant à des faux positifs potentiels signalés dans les octets privés de votre application , votre application peut également finir par allouer de la mémoire à l'intérieur des modules partagés , conduisant à des faux négatifs . Cela signifie qu'il est en fait possible que votre application ait une fuite de mémoire qui ne se manifeste jamais du tout dans les octets privés. Peu probable, mais possible.

Les octets privés sont une approximation raisonnable de la quantité de mémoire utilisée par votre exécutable et peuvent être utilisés pour réduire une liste de candidats potentiels pour une fuite de mémoire; si vous voyez le nombre augmenter et croître constamment et sans cesse, vous voudrez vérifier ce processus pour une fuite. Cela ne peut cependant pas prouver qu'il y a ou non une fuite.

L'un des outils les plus efficaces pour détecter / corriger les fuites de mémoire dans Windows est en fait Visual Studio (le lien va à la page sur l'utilisation de VS pour les fuites de mémoire, pas la page du produit). Rational Purify est une autre possibilité. Microsoft a également un document de bonnes pratiques plus général sur ce sujet. D'autres outils sont répertoriés dans cette question précédente .

J'espère que cela clarifie certaines choses! La recherche des fuites de mémoire est l'une des choses les plus difficiles à faire lors du débogage. Bonne chance.


26
Je crains que votre réponse ne soit pas tout à fait correcte. Les octets privés font référence à la quantité de mémoire (RAM) que l'exécutable du processus a demandée - pas seulement la mémoire physique. Ainsi, vous pouvez sûrement inspecter la plupart des cas de fuite de mémoire en surveillant les octets privés. Essayez :: VisualAlloc pour valider une grande partie de la mémoire (par exemple 1,5 G). Vous devriez pouvoir voir que vos octets privés sont bien plus volumineux que l'ensemble de travail. Ce qui prouve que votre "Working Set est les octets privés plus les fichiers mappés en mémoire" est incorrect.
Jay Zhu

4
En fait, je crois que la compréhension de l'écriture est "Working Set est les octets privés en mémoire plus les fichiers mappés en mémoire". Et les octets privés peuvent être échangés - vous pouvez voir des octets privés plus grands que la mémoire physique que vous avez dans la machine.
Jay Zhu

2
@Aaronaught: Votre première déclaration sur un indicateur fiable et approprié pour le débogage est déroutante. Les octets privés sont un indicateur fiable d'une fuite de l'espace mémoire de l'application. Il peut s'agir d'une DLL dépendante et indirecte, mais il s'agit d'une fuite dans l'espace mémoire de l'application. Pouvez-vous expliquer pourquoi il ne peut pas être utilisé pour le débogage? un vidage complet de la mémoire du processus d'application devrait nous dire ce qui consomme cette mémoire. Je ne suis pas sûr de comprendre pourquoi il ne peut pas être utilisé pour le débogage. Pouvez-vous faire la lumière?
G33kKahuna

@ G33kKahuna: Je ne comprends pas très bien comment un vidage de mémoire vous dirait ce qui consomme la mémoire dans un sens - à moins que par "ce que" vous voulez dire "quels modules", mais alors tout ce que vous avez est un instantané, vous ne pouvez toujours pas voir quel module fuit réellement la mémoire au fil du temps, sauf si vous effectuez plusieurs vidages au fil du temps et dans des conditions étroitement contrôlées. Il est difficile de concevoir une stratégie de débogage plus inefficace et peu fiable. Les profileurs sont partout de nos jours; en utiliser un.
Aaronaught

1
Exécutez un! Objsize complet, cela devrait montrer tous les objets épinglés dans le tas immédiat. Vous pouvez confirmer en vérifiant le eeheap -gc. Cela devrait vous montrer où le volume est bloqué. En règle générale, si aucun indice n'est disponible avec toutes les commandes ci-dessus, vos octets privés sont consommés par des objets non collectés dans GC. Passez maintenant à gchandles ou gcleaks. Ces commandes devraient vous indiquer quels types / adresse d'objet ne peuvent pas être mappés. Le pointeur est toujours là mais l'objet a disparu. Il s'agit d'un problème catégorique pour les gestionnaires d'événements non publiés.
G33kKahuna

10

Vous ne devez pas essayer d'utiliser perfmon, le gestionnaire de tâches ou tout autre outil de ce type pour déterminer les fuites de mémoire. Ils sont bons pour identifier les tendances, mais pas grand-chose d'autre. Les chiffres qu'ils rapportent en termes absolus sont trop vagues et agrégés pour être utiles pour une tâche spécifique telle que la détection de fuite de mémoire.

Une réponse précédente à cette question a donné une grande explication de ce que sont les différents types.

Vous posez des questions sur une recommandation d'outil: je recommande le validateur de mémoire. Capable de surveiller des applications qui font des milliards d'allocations de mémoire.

http://www.softwareverify.com/cpp/memory/index.html

Avertissement: j'ai conçu le validateur de mémoire.


1
Je ne peux même pas exécuter un simple fichier de classe (en Java)? Ce qui donne?
jn1kk

Je soupçonne que Stephen et Devil sont en quelque sorte liés ou même clonés ...: D;)
Robert Koritnik

@StephenKellett, Existe-t-il une version d'essai?
Pacerier

@Pacerier si vous suivez le lien, il y a un essai pour les versions x86 et x64 juste au-dessus de l'option d'achat à gauche de la page.
Bradley A. Tetreault

10

La définition des compteurs perfmon a été rompue depuis le début et, pour une raison quelconque, semble trop difficile à corriger.

Un bon aperçu de la gestion de la mémoire Windows est disponible dans la vidéo " Mysteries of Memory Management Revealed " sur MSDN: il couvre plus de sujets que nécessaire pour suivre les fuites de mémoire (par exemple la gestion des ensembles de travail) mais donne suffisamment de détails dans les sujets pertinents.


Pour vous donner un aperçu du problème avec les descriptions des compteurs perfmon, voici l'histoire intérieure des octets privés de " Compteur de performances des octets privés - Attention! " Sur MSDN:

Q: Quand un octet privé n'est-il pas un octet privé?

R: Quand il n'est pas résident.

Le compteur d'octets privés signale la charge de validation du processus. C'est-à-dire la quantité d'espace qui a été allouée dans le fichier d'échange pour contenir le contenu de la mémoire privée en cas d'échange. Remarque: j'évite le mot "réservé" en raison d'une confusion possible avec la mémoire virtuelle à l'état réservé qui n'est pas validée.


Dans " Planification des performances " sur MSDN:

3.3 Octets privés

3.3.1 Description

La mémoire privée est définie comme la mémoire allouée à un processus qui ne peut pas être partagée par d'autres processus. Cette mémoire est plus chère que la mémoire partagée lorsque plusieurs de ces processus s'exécutent sur une machine. La mémoire privée dans les DLL non gérées (traditionnelles) constitue généralement de la statique C ++ et est de l'ordre de 5% de l'ensemble de travail total de la DLL.


1
vote en raison des exemples incroyablement bons sur la façon dont il est cassé!
Bruno Brant

La première citation est erronée. L'allocation d '"octets privés" ne nécessite rien d'être "alloué dans le fichier d'échange" (qui est vraiment appelé le fichier d'échange). Vous n'avez même pas besoin d'avoir un fichier d'échange pour les "octets privés" à allouer. En fait, l'allocation d'octets privés n'utilise immédiatement aucun espace n'importe où , et peut ne jamais utiliser autant que ce qui a été alloué.
Jamie Hanrahan

La deuxième citation n'est pas beaucoup mieux. Les octets privés utilisés dans le code DLL ne sont pas nécessairement principalement alloués statiquement dans la DLL. Le code DLL est parfaitement libre d'appeler VirtualAlloc, HeapAlloc (malloc et nouveau dans la CRTL), etc. Il essaie également de décrire la taille de la mémoire privée en pourcentage de la taille de l'ensemble de travail, ce qui est absurde. Le premier est une taille virtuelle (et sera le même pour chaque utilisation du code avec la même entrée) tandis que le second est physique (qui peut être radicalement différent d'une exécution à l'autre, selon la quantité de mémoire ou - affamé la machine est).
Jamie Hanrahan

5

Il y a une discussion intéressante ici: http://social.msdn.microsoft.com/Forums/en-US/vcgeneral/thread/307d658a-f677-40f2-bdef-e6352b0bfe9e/ Ma compréhension de ce fil est que la libération de petites allocations est ne se reflète pas dans les octets privés ou l'ensemble de travail.

Longue histoire courte:

si j'appelle

p=malloc(1000);
free(p);

alors les octets privés reflètent uniquement l'allocation, pas la désallocation.

si j'appelle

p=malloc(>512k);
free(p);

alors les octets privés reflètent correctement l'allocation et la désallocation.


7
Cela s'explique par le fait que les fonctions de mémoire de bibliothèque standard C utilisent un tas personnalisé ou Win32 qui est un mécanisme de gestion de la mémoire en plus de la gestion de la mémoire au niveau du processus de bas niveau.
Kyberias

@Kyberias, alors comment pouvons-nous descendre en dessous ?
Pacerier

tandis que (1) gratuit (malloc (1000)); // Cela entraînerait-il une augmentation permanente des octets privés?
franckspike

2
@franckspike: non, il augmentera jusqu'à un certain point (généralement environ 4 Ko, mais cela peut varier) puis s'arrêtera, car le CRT réutilisera la mémoire précédemment libérée au lieu de demander de nouvelles pages au système d'exploitation.
Miral

@Pacerier: vous pouvez appeler VirtualAlloc et VirtualFree.
Jamie Hanrahan
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.