2008-09-22 24 views
36

Des outils tels que 'ps' et 'top' signalent différents types d'utilisation de la mémoire, tels que la taille de la machine virtuelle et la taille de l'ensemble résident. Cependant, aucun de ceux-ci n'est l'utilisation réelle de la mémoire:Une façon de déterminer l'utilisation de la mémoire «réelle» d'un processus, c'est-à-dire le RSS sale privé?

  • Le code de programme est partagé entre plusieurs instances du même programme.
  • Le code de programme de bibliothèque partagée est partagé entre tous les processus qui utilisent cette bibliothèque.
  • Certaines applications déclenchent des processus et partagent de la mémoire avec eux (par exemple via des segments de mémoire partagée).
  • Le système de mémoire virtuelle rend le rapport de taille de VM pratiquement inutile.
  • RSS est 0 lorsqu'un processus est échangé, ce qui le rend peu utile.
  • Etc etc

J'ai trouvé que le RSS sale privé, tel que rapporté par Linux, est la chose la plus proche de l'utilisation de la mémoire « réelle ». Cela peut être obtenu en additionnant toutes les valeurs Private_Dirty dans /proc/somepid/smaps.

Cependant, les autres systèmes d'exploitation offrent-ils des fonctionnalités similaires? Si non, quelles sont les alternatives? En particulier, je suis intéressé par FreeBSD et OS X.

+0

Quelle est exactement la « vraie utilisation de la mémoire »? En fonction de votre liste, l'idée de l'utilisation de la mémoire pour un seul processus est inutile ou arbitraire. – BCS

+2

Je définirais «l'utilisation réelle de la mémoire» comme la quantité de mémoire physique (mais pas d'échange) qui serait libérée si je «tais -9» le processus donné. Je crois que ce nombre devrait être quelque part entre les valeurs RSS et PSS rapportées pour un processus. –

+0

@Hongli: Bien que ce soit un vieux fil de discussion, je suis surpris de voir pourquoi le montage de linprocfs ne faisait pas partie de la solution suggérée par quiconque ici, pour FreeBSD. Y a-t-il une raison spécifique pour cela? J'ai de toute façon ajouté cette réponse pour l'amour de l'achèvement. – Arvind

Répondre

3

Le dessus sait comment faire ceci. Il affiche par défaut VIRT, RES et SHR sur Debian Linux. VIRT = SWAP + RES. RES = CODE + DONNÉES. SHR est la mémoire qui peut être partagée avec un autre processus (bibliothèque partagée ou autre mémoire).

De même, la mémoire «sale» est simplement la mémoire RES qui a été utilisée et/ou n'a pas été permutée.

Cela peut être difficile à dire, mais la meilleure façon de comprendre est de regarder un système qui ne permute pas. Ensuite, RES - SHR est la mémoire exclusive du processus. Cependant, ce n'est pas une bonne façon de voir les choses, car vous ne savez pas que la mémoire de SHR est utilisée par un autre processus. Il peut représenter des pages d'objets partagés non écrits qui ne sont utilisés que par le processus.

+0

Je ne pense pas que ce soit correct. Considérez http://pastie.org/277766 Ceci mappe 300 Mo dans l'espace adresse, mais seul le dernier octet est écrit. L'utilisation réelle de la mémoire pour ce bloc doit être de 4 Ko (taille d'une page). L'utilisation réelle de la mémoire de processus ne doit être que de plusieurs Ko. – Hongli

+0

Toute mémoire inutilisée dans votre exemple apparaîtrait toujours dans le total VIRT. Et le total RES refléterait toute mémoire inutilisée (c'est-à-dire, ne pas le montrer.) Au moins, c'est comme ça que ça fonctionne sur Debian x86. – Chris

+0

Je suis d'accord avec vous. RES-SHR sera un bon moyen d'évaluer l'utilisation de la mémoire de processus pour la plupart des processus. Habituellement, les fuites de mémoire se produisent dans la mémoire privée et c'est ce que vous allez étudier. Si l'on veut connaître l'utilisation complète de la mémoire, il ne doit pas résumer les processus mais aller au début/htop global. – norekhov

4

Vous ne pouvez vraiment pas. Je veux dire, la mémoire partagée entre les processus ... allez-vous compter, ou pas. Si vous ne le comptez pas, vous avez tort; la somme de l'utilisation de la mémoire de tous les processus ne sera pas l'utilisation totale de la mémoire. Si vous le comptez, vous allez le compter deux fois, la somme ne sera pas correcte.

Moi, je suis content avec RSS. Et sachant que vous ne pouvez pas vraiment compter dessus complètement ...

35

Sur OSX le moniteur d'activité vous donne réellement une très bonne estimation. La mémoire privée est pour la mémoire sûre qui est seulement utilisée par votre application. Par exemple. La pile de mémoire et toute la mémoire réservée dynamiquement en utilisant malloc() et les fonctions/méthodes comparables (alloc méthode pour Objective-C) est de la mémoire privée. Si vous utilisez un fork, la mémoire privée sera partagée avec votre enfant, mais marquée copy-on-write. Cela signifie que tant qu'une page n'est modifiée par aucun processus (parent ou enfant), elle est partagée entre eux. Dès que l'un des processus modifie une page, cette page est copiée avant d'être modifiée. Même si cette mémoire est partagée avec les enfants fork (et elle ne peut être partagée qu'avec des fork fork), elle est toujours montrée comme mémoire "privée", car dans le pire des cas, chaque page sera modifiée (tôt ou tard)) puis de nouveau privé à chaque processus.La mémoire partagée est la mémoire actuellement partagée (les mêmes pages sont visibles dans l'espace de processus virtuel de différents processus) ou qui est susceptible de devenir partagée à l'avenir (par exemple, la mémoire en lecture seule, car il n'y a aucune raison pour ne pas partager la mémoire en lecture seule). Au moins, c'est ainsi que j'ai lu le code source de certains outils de ligne de commande d'Apple. Donc, si vous partagez de la mémoire entre des processus utilisant mmap (ou un appel comparable qui mappe la même mémoire en plusieurs processus), ce sera de la mémoire partagée. Cependant, le code exécutable lui-même est également de la mémoire partagée, car si une autre instance de votre application est démarrée, il n'y a aucune raison qu'elle ne partage pas le code déjà chargé en mémoire (les pages de code exécutables sont en lecture seule par défaut). application dans un débogueur). Ainsi, la mémoire partagée est vraiment la mémoire utilisée par votre application, comme celle privée, mais elle peut également être partagée avec un autre processus (ou non, mais pourquoi ne compterait-elle pas dans votre application si elle était partagée?)

La mémoire réelle est la quantité de RAM actuellement "affectée" à votre processus, qu'elle soit privée ou partagée. Cela peut être exactement la somme de privé et partagé, mais habituellement il ne l'est pas. Votre processus peut avoir plus de mémoire qu'il n'en a actuellement besoin (cela accélère les demandes pour plus de mémoire dans le futur), mais ce n'est pas une perte pour le système. Si un autre processus a besoin de mémoire et qu'aucune mémoire libre n'est disponible, avant que le système ne commence à échanger, il enlèvera cette mémoire supplémentaire de votre processus et lui assignera un autre processus (opération rapide et indolore); par conséquent, votre prochain appel malloc pourrait être un peu plus lent. La mémoire réelle peut également être plus petite que la mémoire privée et physique; En effet, si votre processus demande de la mémoire au système, il ne recevra que de la "mémoire virtuelle". Cette mémoire virtuelle n'est liée à aucune page de mémoire réelle tant que vous ne l'utilisez pas (donc 10 Mo de mémoire, n'utilisez qu'un octet, votre processus n'obtiendra qu'une seule page, 4096 octets, de mémoire assignée - le reste n'est attribué que si vous en avez réellement besoin). La mémoire supplémentaire qui est permutée ne peut pas non plus compter pour la mémoire réelle (pas sûr de cela), mais elle comptera pour la mémoire partagée et privée.

La mémoire virtuelle est la somme de tous les blocs d'adresses considérés comme valides dans l'espace de traitement des applications. Ces adresses peuvent être liées à la mémoire physique (à nouveau privée ou partagée), ou elles peuvent ne pas l'être, mais dans ce cas, elles seront liées à la mémoire physique dès que vous utiliserez l'adresse. L'accès aux adresses mémoire en dehors des adresses connues provoquera un SIGBUS et votre application va planter. Lorsque la mémoire est permuté, l'espace d'adressage virtuel pour cette mémoire reste valable et l'accès à ces adresses, la mémoire est raffraîchissement dans

Conclusion:.
Si votre application n'utilise pas explicitement ou implicitement la mémoire partagée, la mémoire privée est la quantité de mémoire dont votre application a besoin en raison de la taille de la pile (ou des tailles si elle est multithread) et des appels malloc() que vous avez faits pour la mémoire dynamique. Vous n'avez pas à vous soucier beaucoup de la mémoire partagée ou réelle dans ce cas. Si votre application utilise de la mémoire partagée, y compris une interface graphique, où la mémoire est partagée entre votre application et le WindowServer par exemple, vous pouvez également consulter la mémoire partagée. Un nombre de mémoire partagée très élevé peut signifier que vous avez trop de ressources graphiques chargées en mémoire pour le moment.

La mémoire réelle n'a que peu d'intérêt pour le développement d'applications. Si elle est plus grande que la somme de partagé et privé, cela ne signifie rien d'autre que que le système est paresseux à la mémoire de votre processus. Si elle est plus petite, votre processus a demandé plus de mémoire que nécessaire, ce qui n'est pas mal non plus, puisque tant que vous n'utilisez pas toute la mémoire demandée, vous ne «volez» pas la mémoire du système.Si elle est beaucoup plus petite que la somme de shared et private, vous ne pouvez envisager de demander moins de mémoire que possible, car vous demandez un peu plus de mémoire (encore une fois, ce n'est pas mauvais, mais cela me dit que votre code n'est pas optimisé pour une utilisation minimale de la mémoire et s'il est multi plate-forme, les autres plates-formes peuvent ne pas avoir un traitement de mémoire aussi sophistiqué, donc vous pouvez préférer allouer beaucoup de petits blocs plutôt que quelques gros blocs. sur).

Si vous n'êtes toujours pas satisfait de toutes ces informations, vous pouvez obtenir encore plus d'informations. Ouvrez un terminal et exécutez:

sudo vmmap <pid> 

où est l'ID de processus de votre processus. Cela vous montrera les statistiques pour EVERY bloc de mémoire dans votre espace de processus avec l'adresse de début et de fin. Il vous dira également d'où vient cette mémoire (un fichier mappé, une pile de mémoire, une mémoire mallocée, une section __DATA ou __TEXT de votre exécutable?), Sa taille en KB, ses droits d'accès et son caractère privé, partagé ou copier-sur-écrire. S'il est mappé à partir d'un fichier, il vous donnera même le chemin d'accès au fichier.

Si vous ne souhaitez que l'utilisation de la RAM « réelle », utilisez

sudo vmmap -resident <pid> 

Maintenant, il affichera pour chaque bloc de mémoire la taille du bloc de mémoire est virtuellement et combien il est vraiment actuellement présent dans la mémoire physique.

À la fin de chaque sauvegarde est également une table de synthèse avec la somme des différents types de mémoire. Cette table ressemble à ceci pour Firefox maintenant sur mon système:

REGION TYPE    [ VIRTUAL/RESIDENT] 
===========    [ =======/========] 
ATS (font support)  [ 33.8M/ 2496K] 
CG backing stores  [ 5588K/ 5460K] 
CG image    [  20K/  20K] 
CG raster data   [ 576K/ 576K] 
CG shared images  [ 2572K/ 2404K] 
Carbon     [ 1516K/ 1516K] 
CoreGraphics   [  8K/  8K] 
IOKit     [ 256.0M/  0K] 
MALLOC     [ 256.9M/ 247.2M] 
Memory tag=240   [  4K/  4K] 
Memory tag=242   [  12K/  12K] 
Memory tag=243   [  8K/  8K] 
Memory tag=249   [ 156K/  76K] 
STACK GUARD    [ 101.2M/ 9908K] 
Stack     [ 14.0M/ 248K] 
VM_ALLOCATE    [ 25.9M/ 25.6M] 
__DATA     [ 6752K/ 3808K] 
__DATA/__OBJC   [  28K/  28K] 
__IMAGE     [ 1240K/ 112K] 
__IMPORT    [ 104K/ 104K] 
__LINKEDIT    [ 30.7M/ 3184K] 
__OBJC     [ 1388K/ 1336K] 
__OBJC/__DATA   [  72K/  72K] 
__PAGEZERO    [  4K/  0K] 
__TEXT     [ 108.6M/ 63.5M] 
__UNICODE    [ 536K/ 512K] 
mapped file    [ 118.8M/ 50.8M] 
shared memory   [ 300K/ 276K] 
shared pmap    [ 6396K/ 3120K] 

Qu'est-ce que cela nous dit? Par exemple. le binaire Firefox et toutes les bibliothèques qu'il charge ont 108 Mo de données ensemble dans leurs sections __TEXT, mais actuellement, seulement 63 Mo de ceux-ci résident actuellement en mémoire. Le support de police (ATS) a besoin de 33 Mo, mais seulement environ 2,5 Mo sont vraiment en mémoire. Il utilise un peu plus de 5 MB de banques de support CG, CG = Core Graphics, ce sont probablement des contenus de fenêtres, des boutons, des images et d'autres données qui sont mises en cache pour un dessin rapide. Il a demandé 256 Mo via des appels malloc et actuellement 247 Mo sont réellement mappés sur des pages mémoire. Il a 14 Mo d'espace réservé pour les piles, mais seulement 248 Ko d'espace de pile est vraiment utilisé en ce moment.

VMMap a aussi un bon résumé ci-dessus la table

ReadOnly portion of Libraries: Total=139.3M resident=66.6M(48%) swapped_out_or_unallocated=72.7M(52%) 
Writable regions: Total=595.4M written=201.8M(34%) resident=283.1M(48%) swapped_out=0K(0%) unallocated=312.3M(52%) 

Et cela montre un aspect intéressant de l'OS X: Pour mémoire en lecture seule, il ne joue aucun rôle si elle est permutée ou simplement non alloué; il n'y a que résident et non résident. Pour la mémoire inscriptible cela fait une différence (dans mon cas 52% de la mémoire demandée n'a jamais été utilisée et est non alloué, 0% de mémoire a été échangé sur le disque)

8

Sur Linux, vous pouvez vouloir le PSS (taille de l'ensemble proportionnel) dans/proc/self/smaps. Le PSS d'un mappage est son RSS divisé par le nombre de processus qui utilisent ce mappage.

4

Vous pouvez obtenir sale et propre privé RSS/proc/pid/smaps

0

privé Pour une question qui a mentionné Freebsd, n'a surpris personne écrit encore ceci:

Si vous voulez un style/proc linux/processId/sortie d'état, s'il vous plaît procédez comme suit:

mount -t linprocfs none /proc 
cat /proc/PROCESSID/status 

Atleast dans FreeBSD 7.0, le montage n'a pas été fait par défaut (7.0 est une version beaucoup plus ancienne, mais pour quelque chose de cette base, la réponse était cachée dans une liste de diffusion!)

1
for i in /proc/[0-9]*; do 
    grep -q 'Private_Dirty' $i/smaps; 
    if [ $? -ne 0 ]; then 
    continue; 
    fi; 
    echo -n "${i}: "; 
    awk '/Private_Dirty/ {print $2,$3}' $i/smaps | 
    sed 's/ tB/*1024 gB/;s/ gB/*1024 mB/;s/ mB/*1024 kB/;s/ kB/*1024/;1!s/^/+/;' | 
    tr -d '\n' | 
    sed 's/$/\n/' | 
    bc | 
    tr -d '\n'; 
    echo; 
done | 
sort -n -k 2 
0

Check it out, c'est le code source de gnome-system-monitor, il pense que la mémoire "vraiment utilisé" par un seul processus est la somme (info->mem) de mémoire X Server (info->memxserver) et inscriptible de mémoire (info->memwritable), le "Writable mémoire" représente les blocs de mémoire qui sont marquées comme "Private_Dirty" dans /proc/PID/smaps fichier.

Autre que le système Linux, pourrait être différente façon selon le code gnome-système-moniteur.

static void 
get_process_memory_writable (ProcInfo *info) 
{ 
    glibtop_proc_map buf; 
    glibtop_map_entry *maps; 

    maps = glibtop_get_proc_map(&buf, info->pid); 

    gulong memwritable = 0; 
    const unsigned number = buf.number; 

    for (unsigned i = 0; i < number; ++i) { 
#ifdef __linux__ 
     memwritable += maps[i].private_dirty; 
#else 
     if (maps[i].perm & GLIBTOP_MAP_PERM_WRITE) 
      memwritable += maps[i].size; 
#endif 
    } 

    info->memwritable = memwritable; 

    g_free(maps); 
} 

static void 
get_process_memory_info (ProcInfo *info) 
{ 
    glibtop_proc_mem procmem; 
    WnckResourceUsage xresources; 

    wnck_pid_read_resource_usage (gdk_screen_get_display (gdk_screen_get_default()), 
            info->pid, 
            &xresources); 

    glibtop_get_proc_mem(&procmem, info->pid); 

    info->vmsize = procmem.vsize; 
    info->memres = procmem.resident; 
    info->memshared = procmem.share; 

    info->memxserver = xresources.total_bytes_estimate; 

    get_process_memory_writable(info); 

    // fake the smart memory column if writable is not available 
    info->mem = info->memxserver + (info->memwritable ? info->memwritable : info->memres); 
}