Une façon de déterminer l'utilisation "réelle" de la mémoire d'un processus, c.-à-d. RSS privé cochon?
des outils comme 'ps' et' top ' signalent divers types d'utilisations de la mémoire, tels que la taille VM et la taille de L'ensemble résident. Cependant, aucun de ceux-ci ne sont la "vraie" utilisation de la mémoire:
- code de programme est partagé entre plusieurs instances du même programme.
- le code de programme de la bibliothèque partagée est partagé entre tous les processus qui utilisent cette bibliothèque.
- certaines applications dévient des processus et partagent de la mémoire avec eux (par exemple via les segments de mémoire).
- le système de mémoire virtuelle rend le rapport de taille VM pratiquement inutile.
- RSS est 0 lorsqu'un processus est échangé, ce qui le rend peu utile.
- etc.
j'ai trouvé que le RSS sale privé, tel que rapporté par Linux, est la chose la plus proche de la "vraie" utilisation de la mémoire. Cela peut être obtenu en additionnant toutes les valeurs Private_Dirty
dans /proc/somepid/smaps
.
Cependant, d'autres systèmes d'exploitation fournissent des fonctionnalités similaires? Dans la négative, quelles sont les solutions de rechange? En particulier, je suis intéressé par FreeBSD et OS X.
10 réponses
sur OSX le moniteur D'activité vous donne en fait une très bonne idée.
la mémoire privée est à coup sûr une mémoire qui n'est utilisée que par votre application. Par exemple: la mémoire de pile et toute la mémoire dynamiquement réservée en utilisant malloc () et des fonctions/méthodes comparables (méthode alloc pour objectif-C) sont de la mémoire privée. Si vous bifurquez, la mémoire privée sera partagée avec votre enfant, mais marquée copie-sur-Écrire. Cela signifie que tant que la page n'est pas modifiée par le processus (parent ou enfant) il est partagé entre eux. Dès que le processus modifie une page, cette page est copiée avant qu'il soit modifié. Même si cette mémoire est partagée avec les enfants fork (et il peut seulement être partagée avec les enfants fork), il est toujours affiché comme "privé" mémoire, parce que dans le pire des cas, chaque page de celui-ci sera modifié (tôt ou tard) et puis il est à nouveau privé à chaque processus à nouveau.
mémoire partagée est soit mémoire qui est 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é dans le futur (par exemple, mémoire en lecture seule, car il n'y a aucune raison de ne pas partager la mémoire en lecture seule). Du moins, c'est comme ça que je lis le code source de certains outils en ligne de commande D'Apple. Ainsi, si vous partagez de la mémoire entre des processus utilisant mmap (ou un appel comparable qui relie la même mémoire en plusieurs processus), ce serait de la mémoire partagée. Cependant le code exécutable lui-même est aussi mémoire partagée, car si une autre instance de votre application est lancée, il n'y a aucune raison pour 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, sauf si vous utilisez votre application dans un débogueur). Ainsi, la mémoire partagée est vraiment la mémoire utilisée par votre application, tout comme la mémoire privée, mais elle pourrait en outre être partagée avec un autre processus (ou elle pourrait ne pas l'être, mais pourquoi ne compterait-elle pas dans votre application si elle était partagée?)
la mémoire réelle est la quantité de mémoire vive actuellement "assignée" à votre processus, qu'elle soit privée ou partagée. Cela peut être exactement la somme de privé et partagé, mais généralement il n'est pas. Votre processus peut avoir plus de mémoire qui lui est assignée qu'il n'en a besoin actuellement (cela accélère les requêtes pour plus de mémoire à l'avenir), 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 commence à échanger, il enlèvera cette mémoire supplémentaire votre processus et lui assigner un autre processus (qui est une opération rapide et indolore); par conséquent, votre prochain appel malloc pourrait être un peu plus lent. La mémoire réelle peut aussi être plus petite que la mémoire privée et physique; c'est parce que si votre processus demande de la mémoire du système, il ne recevra que de la "mémoire virtuelle". Cette mémoire virtuelle est pas lié à une réelle pages de mémoire tant que vous ne l'utilisez pas (donc malloc 10 MO de mémoire, utilisez uniquement un octet, votre processus obtiendrez une seule page, 4096 octet de mémoire assignée - le reste n'est attribué que si vous avez réellement jamais besoin d'elle). Une autre mémoire qui est échangée peut ne pas compter vers la mémoire réelle non plus (pas sûr à ce sujet), mais il comptera vers la mémoire partagée et privée.
la mémoire virtuelle est la somme de tous les blocs d'adresse qui sont considérés valides dans votre espace de processus apps. Ces adresses peuvent être liées à la mémoire physique (qui est à nouveau privée ou partagée), ou elles peuvent ne pas l'être, mais dans ce cas, elles seront lié à la mémoire physique dès que vous utilisez l'adresse. Accéder à des adresses mémoire en dehors des adresses connues provoquera un SIGBUS et votre application s'écrasera. Lorsque la mémoire est échangée, l'espace d'adresse virtuelle pour cette mémoire reste valide et l'accès à ces adresses provoque la mémoire échangée de nouveau.
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 votre application a besoin en raison de la taille de la pile (ou des tailles si multithreaded) et à cause 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 une mémoire partagée, et cela inclut une interface graphique, où la mémoire est partagée entre votre application et le WindowServer par exemple, alors vous pourriez avoir un regard sur la mémoire partagée aussi bien. Un nombre de mémoire partagée très élevé peut signifier que vous en avez trop ressources graphiques chargé en mémoire à l'instant.
la mémoire réelle est de peu d'intérêt pour le développement d'applications. S'il est plus grand que la somme de partagé et privé, alors cela ne signifie rien d'autre que que le système est paresseux à emporter la mémoire loin de votre processus. S'il est plus petit, alors votre processus a demandé plus de mémoire qu'il n'en avait réellement besoin, 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 de la système. Si elle est beaucoup plus petite que la somme de partagée et privée, vous pouvez seulement envisager de demander moins de mémoire lorsque c'est possible, car vous êtes un peu sur-demande de mémoire (encore une fois, ce n'est pas mal, mais il me dit que votre code n'est pas optimisé pour l'utilisation minimale de mémoire et s'il est multiplate-forme, d'autres plates-formes peuvent ne pas avoir une manipulation de mémoire aussi sophistiquée, donc vous pouvez préférer allouer beaucoup de petits blocs au lieu de quelques gros par exemple, ou la mémoire libre beaucoup plus tôt, et ainsi de suite).
Si vous n'êtes toujours pas satisfait avec toutes ses informations, vous pouvez obtenir encore plus d'informations. Ouvrez un terminal et lancez:
sudo vmmap <pid>
où est le numéro de processus de votre processus. Cela vous montrera les statistiques pour chaque bloc de mémoire dans votre espace de processus avec l'adresse de début et de fin. Il vous dira aussi d'où vient cette mémoire (un fichier mappé? La pile de la mémoire? Malloc ed de mémoire? Une section __DATA ou _ _ TEXT de votre exécutable?), comment grand il est en KB, les droits d'accès et s'il est privé, partagé ou copie-sur-écrit. S'il est mappé à partir d'un fichier, il vous donnera même le chemin du fichier.
si vous ne voulez que L'utilisation" réelle "de la mémoire vive, utilisez
sudo vmmap -resident <pid>
maintenant, il va montrer pour chaque bloc de mémoire Comment grand le bloc de mémoire est virtuellement et combien de lui est réellement présent dans la mémoire physique.
à la fin de chaque dump est également un tableau d'ensemble avec la somme des différents types de mémoire. Cette table ressemble à cela pour Firefox en ce moment 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 ça 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 __texte, mais actuellement seulement 63 Mo de ceux qui résident actuellement en mémoire. La prise en charge de la police (ATS) nécessite 33 Mo, mais seulement environ 2,5 Mo sont réellement en mémoire. Il utilise un peu plus de 5 Mo de supports CG magasins, CG = graphiques de base, ceux sont les plus susceptibles contenu de la fenêtre, des boutons, des images et d'autres données qui est mis en cache pour le dessin rapide. Il a demandé 256 Mo via des appels malloc et actuellement 247 Mo sont vraiment en mapped à des pages de mémoire. Il y a 14 Mo d'espace réservé pour les piles, mais seulement 248 Ko d'espace de pile est réellement utilisé en ce moment.
vmmap a également un bon résumé au-dessus du tableau
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 lire seulement la mémoire il ne joue aucun rôle si elle est échangée il n'y a que les résidents et non les résidents. Pour la mémoire en écriture, cela fait une différence (dans mon cas, 52% de toute la mémoire demandée n'a jamais été utilisée et n'est donc pas affectée, 0% de la mémoire a été échangée sur un disque)
sur Linux, vous pouvez vouloir les nombres PSS (proportional set size) dans /proc/self/smaps. Le PSS d'un mapping est son RSS divisé par le nombre de processus qui utilisent ce mapping.
Top sait faire ça. Il affiche VIRT, RES et SHR par défaut sur Debian Linux. VIRT = SWAP + RES. RES = CODE + DONNÉES. SHR est la mémoire qui peut être partagé avec un autre processus (bibliothèque partagée ou autre mémoire.)
en outre, la mémoire "sale" est simplement la mémoire RES qui a été utilisée, et/ou n'a pas été échangée.
cela peut être difficile à dire, mais la meilleure façon de comprendre est de regarder un système qui ne change pas. Alors, RES-SHR est le le processus exclusif de la mémoire. Cependant, ce n'est pas une bonne façon de le voir, parce que vous ne savez pas que la mémoire dans SHR est utilisée par un autre processus. Il peut représenter des pages d'objet partagées non écrites qui ne sont utilisées que par le processus.
tu ne peux vraiment pas.
je veux dire, mémoire partagée entre les processus... allez-vous de les compter, ou pas. Si vous ne le comptez pas, vous vous trompez; 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 comptez, vous allez compter deux fois la somme ne sera pas correcte.
Moi, je suis heureux avec les flux RSS. Et savoir qu'on ne peut pas vraiment compter dessus complètement...
vous pouvez Vous procurer private sale et privé propre flux RSS à partir de /proc/pid/smaps
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 ,}' $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
pour une question qui mentionnait Freebsd, personne n'a encore écrit ceci:
si vous voulez une sortie linux style /proc/PROCESSID/status, veuillez faire ce qui suit:
mount -t linprocfs none /proc
cat /proc/PROCESSID/status
du moins sous 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 d'aussi basique, la réponse était cachée dans une liste de diffusion!)
Check it out, c'est le code source de gnome-System-monitor, il pense que la mémoire " vraiment utilisé " par un processus est somme( info->mem
) de la mémoire du serveur X( info->memxserver
) et la mémoire inscriptible( info->memwritable
), le" Writable Memory "est les blocs de mémoire qui sont marqués comme" Private_Dirty " dans /proc/PID/smaps fichier.
autres que système linux, pourrait être de manière différente selon gnome-système-moniteur code.
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);
}
utiliser l'appel système mincore(2). Citant la page de manuel:
DESCRIPTION
The mincore() system call determines whether each of the pages in the
region beginning at addr and continuing for len bytes is resident. The
status is returned in the vec array, one character per page. Each
character is either 0 if the page is not resident, or a combination of
the following flags (defined in <sys/mman.h>):