Come ottenere l'utilizzo della memoria in fase di esecuzione utilizzando C ++?


90

Ho bisogno di ottenere l'utilizzo di mem VIRT e RES in fase di esecuzione del mio programma e visualizzarli.

Quello che ho provato finora:

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;

ma ottengo sempre 0.


3
Questo dipende dal sistema - sembra che il tuo sistema non supporti la segnalazione di maxrss tramite getrusage - puoi dirci quale distribuzione stai utilizzando?
tvanfosson

Risposte:


79

Su Linux, non ho mai trovato una soluzione ioctl () . Per le nostre applicazioni, abbiamo codificato una routine di utilità generale basata sulla lettura dei file in / proc / pid . Ci sono molti di questi file che danno risultati diversi. Ecco quello su cui abbiamo deciso (la domanda è stata contrassegnata come C ++ e abbiamo gestito l'I / O utilizzando costrutti C ++, ma dovrebbe essere facilmente adattabile alle routine C i / o se necessario):

#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;
}

hai qualche garanzia sulla struttura / proc / self / stat su piattaforme * nix differenti? ... Non ne sono sicuro, ma se sì, sarà carino.
bayda

Ebbene, negli anni ho utilizzato principalmente Solaris, HP-UX e Linux. / proc / self / stat sembra essere un Linux-ism. La versione originale del programma precedente aveva blocchi #if per Solaris poiché differiva.
Don Wakefield,

Presumo che l'OP si preoccupi solo di Linux in base al tagging delle domande. La lettura di / proc sarà buona quanto si ottiene. Su Solaris puoi anche ottenere informazioni su tutti i tipi di cose tramite kstat (sebbene spesso replichi ciò che puoi ottenere con altri mezzi).
stsquad

Sono in ritardo di solo 10 anni per la festa, ma ti dispiacerebbe dirmi perché dividi vsize per 1024.0 anziché 1024?
a_river_in_canada

1
ri: why 1024.0?- Dice al compilatore di convertire PRIMA in double e poi di fare la divisione per ottenere il doppio risultato. L'altra scelta: vm_usage = vsize / 1024;farebbe prima il divario (perdendo precisione come suggerito da @DonWakefield) e poi convertirò in raddoppio.
Jesse Chisholm

52

David Robert Nadeau ha inserito una buona funzione C multi-piattaforma autonoma per ottenere la dimensione del set residente del processo (utilizzo della memoria fisica) nel suo sito 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
}

Utilizzo

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

Per ulteriori discussioni, controllare il sito Web, fornisce anche una funzione per ottenere la dimensione della memoria fisica di un sistema .


2
era meglio aggiungere #pragma comment(lib, "psapi.lib")al #if defined(_WIN32)campo di applicazione.
Bloodmoon

1
@ Bloodmon cosa succede se qualcuno utilizza Windows ma non un compilatore Microsoft? Quel pragma farebbe fallire il compilatore.
Adrian

Questo codice usa rusage :: ru_maxrss da getrusage, che l'OP ha segnalato come non funzionante per lei.
facetus

21

Vecchio:

maxrss indica la memoria massima disponibile per il processo. 0 significa che non viene posto alcun limite al processo. Quello che probabilmente vuoi è l'utilizzo dei dati non condiviso ru_idrss.

Novità: sembra che quanto sopra non funzioni effettivamente, poiché il kernel non riempie la maggior parte dei valori. Quello che funziona è ottenere le informazioni da proc. Invece di analizzarlo da soli, è più facile usare libproc (parte di procps) come segue:

// 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);
}

Compila con " gcc -o getrusage getrusage.c -lproc"


1
Tranne che nessuno dei due campi è disponibile in Linux.
jmanning2k

2
Questo non è corretto. maxrss è il picco di utilizzo della memoria del processo, non il massimo disponibile - sarebbe getrlimit (RLIMIT_DATA, & rl).
jmanning2k

1
La #include <proc/readproc.h>soluzione ha funzionato alla grande per me con Ubuntu. Ho dovuto installare il pacchetto libproc-dev. usage.vm_dataè un'approssimazione abbastanza vicina a ciò di cui avevo bisogno. La tua scelta di statistiche sulla memoria è documentata qui: /usr/include/proc/readproc.hQuelle che ho provato sembrano essere tutte in byte, non in pagine. Non credo che il mio processo stia utilizzando 46 milioni di pagine. I commenti che questa soluzione non funziona sotto Linux sembrano fuorvianti.
Allan Stokes

2
Il linker corretto è: -lprocps
Sembiance

Funziona alla grande, questa dovrebbe essere la risposta accettata!
Pekov


8

Un modo più elegante per il metodo 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;
}

7

Le risposte esistenti sono migliori per come ottenere il valore corretto, ma posso almeno spiegare perché getrusage non funziona per te.

uomo 2 getrusage:

La struttura di cui sopra [rusage] è stata presa da BSD 4.3 Reno. Non tutti i campi sono significativi sotto Linux. Al momento (Linux 2.4, 2.6) vengono mantenuti solo i campi ru_utime, ru_stime, ru_minflt, ru_majflt e ru_nswap.


3

in aggiunta al tuo modo
puoi chiamare il comando ps di sistema e ottenere l'utilizzo della memoria dall'output.
o leggi le informazioni da / proc / pid (vedi PIOCPSINFO struct)


PIOCPSINFO non è realmente disponibile su nessun Linux che ho usato. Leggere da / proc / pid è abbastanza comune. Inserirò un codice di esempio per Linux in una risposta ...
Don Wakefield,

Sì, le strutture / proc / pid possono essere diverse in diverse piattaforme * nix, ma se hai PIOCPSINFO non importa. Ho avuto situazioni in cui questa struttura non era definita su alcune versioni di Solaris .. In questo caso ho usato l'output di ps.
bayda

2

Sul tuo sistema c'è un file chiamato /proc/self/statm. Il filesystem proc è uno pseudo-filesystem che fornisce un'interfaccia alle strutture dati del kernel. Questo file contiene le informazioni necessarie nelle colonne con solo numeri interi separati da spazi.

N. colonna:

  1. = dimensione totale del programma (VmSize in / proc / [pid] / status)

  2. = dimensione del set residente (VmRSS in / proc / [pid] / status)

Per maggiori informazioni vedere il LINK .


1

Sto usando un altro modo per farlo e sembra realistico. Quello che faccio è ottenere il PID del processo dalla funzione getpid () e quindi utilizzare il file / proc / pid / stat. Credo che la 23a colonna del file stat sia vmsize (guarda il post di Don). È possibile leggere vmsize dal file ovunque sia necessario nel codice. Nel caso ti chiedessi quanto uno snippet di codice possa utilizzare la memoria, puoi leggere quel file una volta prima di quel frammento e una volta dopo e puoi sottrarli l'uno dall'altro.


1

Basato sulla soluzione di Don W., con meno variabili.

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;
}

0

Stavo cercando un'app Linux per misurare la memoria massima utilizzata. valgrind è uno strumento eccellente, ma mi dava più informazioni di quanto volessi. tstime sembrava essere lo strumento migliore che potessi trovare. Misura l'utilizzo della memoria "highwater" (RSS e virtuale). Vedi questa risposta .

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.