Comment utiliser la mémoire au moment de l'exécution en utilisant C ++?

90

J'ai besoin d'obtenir l'utilisation de mem VIRT et RES au moment de l'exécution de mon programme et les afficher.

Ce que j'ai essayé jusqu'à présent:

getrusage ( http://linux.die.net/man/2/getrusage )

int who = RUSAGE_SELF; 
struct rusage usage; 
int ret; 

ret=getrusage(who,&usage);

cout<<usage.ru_maxrss;

mais j'obtiens toujours 0.

jww
la source
3
Cela dépend du système - il semble que votre système ne prenne pas en charge les rapports maxrss via getrusage - pouvez-vous nous dire quelle distribution vous utilisez?
tvanfosson

Réponses:

79

Sous Linux, je n'ai jamais trouvé de solution ioctl () . Pour nos applications, nous avons codé une routine utilitaire générale basée sur la lecture de fichiers dans / proc / pid . Il existe un certain nombre de ces fichiers qui donnent des résultats différents. Voici celle sur laquelle nous nous sommes installés (la question était étiquetée C ++, et nous avons géré les E / S en utilisant des constructions C ++, mais elle devrait être facilement adaptable aux routines C i / o si vous en avez besoin):

#include <unistd.h>
#include <ios>
#include <iostream>
#include <fstream>
#include <string>

//////////////////////////////////////////////////////////////////////////////
//
// process_mem_usage(double &, double &) - takes two doubles by reference,
// attempts to read the system-dependent data for a process' virtual memory
// size and resident set size, and return the results in KB.
//
// On failure, returns 0.0, 0.0

void process_mem_usage(double& vm_usage, double& resident_set)
{
   using std::ios_base;
   using std::ifstream;
   using std::string;

   vm_usage     = 0.0;
   resident_set = 0.0;

   // 'file' stat seems to give the most reliable results
   //
   ifstream stat_stream("/proc/self/stat",ios_base::in);

   // dummy vars for leading entries in stat that we don't care about
   //
   string pid, comm, state, ppid, pgrp, session, tty_nr;
   string tpgid, flags, minflt, cminflt, majflt, cmajflt;
   string utime, stime, cutime, cstime, priority, nice;
   string O, itrealvalue, starttime;

   // the two fields we want
   //
   unsigned long vsize;
   long rss;

   stat_stream >> pid >> comm >> state >> ppid >> pgrp >> session >> tty_nr
               >> tpgid >> flags >> minflt >> cminflt >> majflt >> cmajflt
               >> utime >> stime >> cutime >> cstime >> priority >> nice
               >> O >> itrealvalue >> starttime >> vsize >> rss; // don't care about the rest

   stat_stream.close();

   long page_size_kb = sysconf(_SC_PAGE_SIZE) / 1024; // in case x86-64 is configured to use 2MB pages
   vm_usage     = vsize / 1024.0;
   resident_set = rss * page_size_kb;
}

int main()
{
   using std::cout;
   using std::endl;

   double vm, rss;
   process_mem_usage(vm, rss);
   cout << "VM: " << vm << "; RSS: " << rss << endl;
}
Don Wakefield
la source
avez-vous des garanties sur la structure / proc / self / stat sous différentes plates-formes * nix? ... Je ne suis pas sûr, mais si oui, ce sera bien.
bayda
Eh bien, au fil des ans, j'ai principalement utilisé Solaris, HP-UX et Linux. / proc / self / stat semble être un Linux-ism. La version originale du programme ci-dessus avait des blocs #if pour Solaris car elle différait.
Don Wakefield
Je suppose que l'OP ne se soucie que de Linux en fonction du balisage des questions. La lecture / proc sera à peu près aussi bonne que vous. Sur Solaris, vous pouvez également obtenir des informations sur toutes sortes de choses via kstat (bien qu'il reproduise souvent ce que vous pouvez obtenir par d'autres moyens).
stsquad
Je n'ai que 10 ans de retard à la fête, mais pourriez-vous me dire pourquoi vous divisez vsize par 1024,0 plutôt que 1024?
a_river_in_canada
1
re: why 1024.0?- Il dit au compilateur de convertir en double FIRST puis de faire la division pour obtenir le double résultat. L'autre choix: vm_usage = vsize / 1024;ferait la division en premier, (perdant de la précision comme l'indique @DonWakefield), puis convertirait en double.
Jesse Chisholm
52

David Robert Nadeau a mis une bonne fonction C multi-plateforme autonome pour obtenir la taille de l'ensemble du processus résident (utilisation de la mémoire physique) dans son site Web:

/*
 * Author:  David Robert Nadeau
 * Site:    http://NadeauSoftware.com/
 * License: Creative Commons Attribution 3.0 Unported License
 *          http://creativecommons.org/licenses/by/3.0/deed.en_US
 */

#if defined(_WIN32)
#include <windows.h>
#include <psapi.h>

#elif defined(__unix__) || defined(__unix) || defined(unix) || (defined(__APPLE__) && defined(__MACH__))
#include <unistd.h>
#include <sys/resource.h>

#if defined(__APPLE__) && defined(__MACH__)
#include <mach/mach.h>

#elif (defined(_AIX) || defined(__TOS__AIX__)) || (defined(__sun__) || defined(__sun) || defined(sun) && (defined(__SVR4) || defined(__svr4__)))
#include <fcntl.h>
#include <procfs.h>

#elif defined(__linux__) || defined(__linux) || defined(linux) || defined(__gnu_linux__)
#include <stdio.h>

#endif

#else
#error "Cannot define getPeakRSS( ) or getCurrentRSS( ) for an unknown OS."
#endif





/**
 * Returns the peak (maximum so far) resident set size (physical
 * memory use) measured in bytes, or zero if the value cannot be
 * determined on this OS.
 */
size_t getPeakRSS( )
{
#if defined(_WIN32)
    /* Windows -------------------------------------------------- */
    PROCESS_MEMORY_COUNTERS info;
    GetProcessMemoryInfo( GetCurrentProcess( ), &info, sizeof(info) );
    return (size_t)info.PeakWorkingSetSize;

#elif (defined(_AIX) || defined(__TOS__AIX__)) || (defined(__sun__) || defined(__sun) || defined(sun) && (defined(__SVR4) || defined(__svr4__)))
    /* AIX and Solaris ------------------------------------------ */
    struct psinfo psinfo;
    int fd = -1;
    if ( (fd = open( "/proc/self/psinfo", O_RDONLY )) == -1 )
        return (size_t)0L;      /* Can't open? */
    if ( read( fd, &psinfo, sizeof(psinfo) ) != sizeof(psinfo) )
    {
        close( fd );
        return (size_t)0L;      /* Can't read? */
    }
    close( fd );
    return (size_t)(psinfo.pr_rssize * 1024L);

#elif defined(__unix__) || defined(__unix) || defined(unix) || (defined(__APPLE__) && defined(__MACH__))
    /* BSD, Linux, and OSX -------------------------------------- */
    struct rusage rusage;
    getrusage( RUSAGE_SELF, &rusage );
#if defined(__APPLE__) && defined(__MACH__)
    return (size_t)rusage.ru_maxrss;
#else
    return (size_t)(rusage.ru_maxrss * 1024L);
#endif

#else
    /* Unknown OS ----------------------------------------------- */
    return (size_t)0L;          /* Unsupported. */
#endif
}





/**
 * Returns the current resident set size (physical memory use) measured
 * in bytes, or zero if the value cannot be determined on this OS.
 */
size_t getCurrentRSS( )
{
#if defined(_WIN32)
    /* Windows -------------------------------------------------- */
    PROCESS_MEMORY_COUNTERS info;
    GetProcessMemoryInfo( GetCurrentProcess( ), &info, sizeof(info) );
    return (size_t)info.WorkingSetSize;

#elif defined(__APPLE__) && defined(__MACH__)
    /* OSX ------------------------------------------------------ */
    struct mach_task_basic_info info;
    mach_msg_type_number_t infoCount = MACH_TASK_BASIC_INFO_COUNT;
    if ( task_info( mach_task_self( ), MACH_TASK_BASIC_INFO,
        (task_info_t)&info, &infoCount ) != KERN_SUCCESS )
        return (size_t)0L;      /* Can't access? */
    return (size_t)info.resident_size;

#elif defined(__linux__) || defined(__linux) || defined(linux) || defined(__gnu_linux__)
    /* Linux ---------------------------------------------------- */
    long rss = 0L;
    FILE* fp = NULL;
    if ( (fp = fopen( "/proc/self/statm", "r" )) == NULL )
        return (size_t)0L;      /* Can't open? */
    if ( fscanf( fp, "%*s%ld", &rss ) != 1 )
    {
        fclose( fp );
        return (size_t)0L;      /* Can't read? */
    }
    fclose( fp );
    return (size_t)rss * (size_t)sysconf( _SC_PAGESIZE);

#else
    /* AIX, BSD, Solaris, and Unknown OS ------------------------ */
    return (size_t)0L;          /* Unsupported. */
#endif
}

Usage

size_t currentSize = getCurrentRSS( );
size_t peakSize    = getPeakRSS( );

Pour plus de discussion, consultez le site Web, il fournit également une fonction permettant d'obtenir la taille de la mémoire physique d'un système .

pepper_chico
la source
2
mieux vaut ajouter #pragma comment(lib, "psapi.lib")à la #if defined(_WIN32)portée.
Bloodmoon
1
@Bloodmon et si quelqu'un utilise Windows mais pas un compilateur Microsoft? Ce pragma ferait échouer le compilateur.
Adrian
Ce code utilise rusage :: ru_maxrss de getrusage, que l'OP a signalé comme ne fonctionnant pas pour elle.
facetus
21

Vieux:

maxrss indique la mémoire maximale disponible pour le processus. 0 signifie qu'aucune limite n'est imposée au processus. Ce que vous voulez probablement, c'est une utilisation des données non partagées ru_idrss.

Nouveau: il semble que ce qui précède ne fonctionne pas réellement, car le noyau ne remplit pas la plupart des valeurs. Ce qui fonctionne, c'est d'obtenir les informations de proc. Au lieu de l'analyser soi-même, il est plus facile d'utiliser libproc (qui fait partie de procps) comme suit:

// getrusage.c
#include <stdio.h>
#include <proc/readproc.h>

int main() {
  struct proc_t usage;
  look_up_our_self(&usage);
  printf("usage: %lu\n", usage.vsize);
}

Compilez avec " gcc -o getrusage getrusage.c -lproc"

Paul de Vrieze
la source
1
Sauf qu'aucun de ces champs n'est disponible sous Linux.
jmanning2k
2
Ceci est une erreur. maxrss est l'utilisation maximale de la mémoire du processus, pas le maximum disponible - ce serait getrlimit (RLIMIT_DATA, & rl).
jmanning2k
1
La #include <proc/readproc.h>solution a très bien fonctionné pour moi sous Ubuntu. J'ai dû installer le package libproc-dev. usage.vm_dataest une approximation assez proche de ce dont j'avais besoin. Votre choix de statistique de mémoire est documenté ici: /usr/include/proc/readproc.hceux que j'ai essayés semblent tous être en octets, pas en pages. Je ne pense pas que mon processus utilisait 46 millions de pages. Les commentaires selon lesquels cette solution ne fonctionne pas sous Linux semblent erronés.
Allan Stokes
2
L'éditeur de liens correct est: -lprocps
Sembiance
Fonctionne très bien, celle-ci devrait être la réponse acceptée!
Pekov
9

Sous Linux, si vous pouvez vous permettre le coût d'exécution (pour le débogage), vous pouvez utiliser valgrind avec l'outil massif:

http://valgrind.org/docs/manual/ms-manual.html

C'est lourd, mais très utile.

David Cournapeau
la source
8

Une manière plus élégante pour la méthode Don Wakefield:

#include <iostream>
#include <fstream>

using namespace std;

int main(){

    int tSize = 0, resident = 0, share = 0;
    ifstream buffer("/proc/self/statm");
    buffer >> tSize >> resident >> share;
    buffer.close();

    long page_size_kb = sysconf(_SC_PAGE_SIZE) / 1024; // in case x86-64 is configured to use 2MB pages
    double rss = resident * page_size_kb;
    cout << "RSS - " << rss << " kB\n";

    double shared_mem = share * page_size_kb;
    cout << "Shared Memory - " << shared_mem << " kB\n";

    cout << "Private Memory - " << rss - shared_mem << "kB\n";
    return 0;
}
Qsiris
la source
7

Les réponses existantes sont meilleures pour obtenir la valeur correcte, mais je peux au moins expliquer pourquoi getrusage ne fonctionne pas pour vous.

homme 2 getrusage:

La structure ci-dessus [rusage] a été tirée de BSD 4.3 Reno. Tous les champs ne sont pas significatifs sous Linux. Pour le moment (Linux 2.4, 2.6), seuls les champs ru_utime, ru_stime, ru_minflt, ru_majflt et ru_nswap sont maintenus.

jmanning2k
la source
3

en plus de votre façon,
vous pouvez appeler la commande système ps et obtenir l'utilisation de la mémoire à partir de sa sortie.
ou lire les informations de / proc / pid (voir struct PIOCPSINFO)

bayda
la source
PIOCPSINFO n'est vraiment disponible sur aucun Linux que j'ai utilisé. La lecture depuis / proc / pid est assez courante. Je posterai un exemple de code pour Linux dans une réponse ...
Don Wakefield
oui Les structures / proc / pid peuvent être différentes dans différentes plates-formes * nix, mais si vous avez PIOCPSINFO, ce n'est pas grave. J'ai eu une situation où cette structure n'était pas définie sur certaines versions de solaris .. J'ai utilisé la sortie ps dans ce cas.
bayda
2

Sur votre système, il y a un fichier nommé /proc/self/statm. Le système de fichiers proc est un pseudo-système de fichiers qui fournit une interface aux structures de données du noyau. Ce fichier contient les informations dont vous avez besoin dans des colonnes avec uniquement des entiers séparés par des espaces.

N ° de colonne:

  1. = taille totale du programme (VmSize dans / proc / [pid] / status)

  2. = taille de l'ensemble résident (VmRSS dans / proc / [pid] / status)

Pour plus d'informations, consultez le LINK .

Jakub Krawczuk
la source
1

J'utilise une autre façon de faire cela et cela semble réaliste. Ce que je fais, c'est que j'ai le PID du processus par la fonction getpid (), puis j'utilise le fichier / proc / pid / stat. Je crois que la 23ème colonne du fichier stat est le vmsize (regardez le post Don). Vous pouvez lire le vmsize du fichier partout où vous en avez besoin dans le code. Si vous vous demandez à quel point un extrait de code peut utiliser de la mémoire, vous pouvez lire ce fichier une fois avant cet extrait et une fois après et vous pouvez les soustraire l'un de l'autre.


la source
1

Basé sur la solution de Don W, avec moins de variables.

void process_mem_usage(double& vm_usage, double& resident_set)
{
    vm_usage     = 0.0;
    resident_set = 0.0;

    // the two fields we want
    unsigned long vsize;
    long rss;
    {
        std::string ignore;
        std::ifstream ifs("/proc/self/stat", std::ios_base::in);
        ifs >> ignore >> ignore >> ignore >> ignore >> ignore >> ignore >> ignore >> ignore >> ignore >> ignore
                >> ignore >> ignore >> ignore >> ignore >> ignore >> ignore >> ignore >> ignore >> ignore >> ignore
                >> ignore >> ignore >> vsize >> rss;
    }

    long page_size_kb = sysconf(_SC_PAGE_SIZE) / 1024; // in case x86-64 is configured to use 2MB pages
    vm_usage = vsize / 1024.0;
    resident_set = rss * page_size_kb;
}
ϹοδεMεδιϲ
la source
0

Je cherchais une application Linux pour mesurer la mémoire maximale utilisée. valgrind est un excellent outil, mais il me donnait plus d'informations que je ne le souhaitais. tstime semblait être le meilleur outil que j'ai pu trouver. Il mesure l'utilisation de la mémoire «highwater» (RSS et virtuelle). Voyez cette réponse .

jtpereyda
la source