Wie kann ich zur Laufzeit mit C ++ die Speichernutzung ermitteln?

89

Ich muss die Mem-Nutzung VIRT und RES zur Laufzeit meines Programms abrufen und anzeigen.

Was ich bisher versucht habe:

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;

aber ich bekomme immer 0.

jww
quelle
2
Dies ist systemabhängig - es scheint, dass Ihr System die Berichterstellung für maxrss über getrusage nicht unterstützt. Können Sie uns mitteilen, welche Distribution Sie verwenden?
Tvanfosson

Antworten:

79

Unter Linux habe ich noch nie eine ioctl () -Lösung gefunden. Für unsere Anwendungen haben wir eine allgemeine Dienstprogrammroutine codiert, die auf dem Lesen von Dateien in / proc / pid basiert . Es gibt eine Reihe dieser Dateien, die unterschiedliche Ergebnisse liefern. Hier ist die, auf die wir uns geeinigt haben (die Frage wurde mit C ++ markiert, und wir haben E / A mit C ++ - Konstrukten behandelt, sie sollte jedoch bei Bedarf leicht an C i / O-Routinen anpassbar sein):

#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
quelle
Haben Sie Garantien für die Struktur / proc / self / stat unter verschiedenen * nix-Plattformen? Ich bin mir nicht sicher, aber wenn ja, wird es schön.
Bayda
Im Laufe der Jahre habe ich hauptsächlich Solaris, HP-UX und Linux verwendet. / proc / self / stat scheint ein Linux-Ismus zu sein. Die ursprüngliche Version des obigen Programms hatte # if-Blöcke für Solaris, da sie sich unterschieden.
Don Wakefield
Ich gehe davon aus, dass sich das OP nur um Linux kümmert, basierend auf dem Frage-Tagging. Lesen / Proc wird so gut wie möglich sein. Unter Solaris können Sie die Informationen zu allen möglichen Dingen auch über kstat abrufen (obwohl häufig repliziert wird, was Sie auf andere Weise erhalten können).
stsquad
Ich bin nur 10 Jahre zu spät zur Party, aber würde es Ihnen etwas ausmachen, mir zu sagen, warum Sie vsize durch 1024.0 statt 1024 teilen?
a_river_in_canada
1
re: why 1024.0?- Der Compiler wird angewiesen, zuerst in double zu konvertieren und dann zu teilen, um das doppelte Ergebnis zu erhalten. Die andere Wahl: vm_usage = vsize / 1024;würde zuerst die Division durchführen (die Genauigkeit verlieren, wie @DonWakefield andeutet) und dann in double konvertieren.
Jesse Chisholm
49

David Robert Nadeau hat eine gute eigenständige Multi-Plattform-C-Funktion hinzugefügt, um die prozessresidente Satzgröße (physische Speichernutzung) auf seiner Website zu ermitteln:

/*
 * 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
}

Verwendung

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

Weitere Informationen finden Sie auf der Website. Dort finden Sie auch eine Funktion zum Abrufen der physischen Speichergröße eines Systems .

Pfeffer_chico
quelle
2
sollte besser #pragma comment(lib, "psapi.lib")zum #if defined(_WIN32)Umfang hinzufügen .
Bloodmoon
1
@Bloodmon was ist, wenn jemand Windows verwendet, aber keinen Microsoft-Compiler? Dieses Pragma würde den Compiler zum Scheitern bringen.
Adrian
Dieser Code verwendet rusage :: ru_maxrss von getrusage, von dem das OP berichtet hat, dass es für sie nicht funktioniert.
Facetus
20

Alt:

maxrss gibt den maximal verfügbaren Speicher für den Prozess an. 0 bedeutet, dass dem Prozess keine Grenzen gesetzt sind. Was Sie wahrscheinlich wollen, ist eine nicht gemeinsam genutzte Datennutzung ru_idrss.

Neu: Es scheint, dass das oben Genannte nicht funktioniert, da der Kernel die meisten Werte nicht ausfüllt. Was funktioniert, ist, die Informationen von proc zu erhalten. Anstatt es selbst zu analysieren, ist es einfacher, libproc (Teil von procps) wie folgt zu verwenden:

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

Kompilieren Sie mit " gcc -o getrusage getrusage.c -lproc"

Paul de Vrieze
quelle
1
Außer, dass unter Linux kein Feld verfügbar ist.
jmanning2k
2
Das ist falsch. maxrss ist die maximale Speichernutzung des Prozesses, nicht die maximal verfügbare - das wäre getrlimit (RLIMIT_DATA, & rl).
jmanning2k
1
Die #include <proc/readproc.h>Lösung hat unter Ubuntu hervorragend funktioniert. Ich musste das Paket installieren libproc-dev. usage.vm_dataist eine Annäherung an das, was ich brauchte. Ihre Wahl der Speicherstatistik ist hier dokumentiert: /usr/include/proc/readproc.hDiejenigen, die ich ausprobiert habe, scheinen alle in Bytes und nicht in Seiten zu sein. Ich glaube nicht, dass mein Prozess 46 Millionen Seiten verwendet hat. Kommentare, dass diese Lösung unter Linux nicht funktioniert, scheinen falsch zu sein.
Allan Stokes
2
Richtiger Linker ist: -lprocps
Sembiance
Funktioniert super, dies sollte die akzeptierte Antwort sein!
Pekov
9

Wenn Sie sich unter Linux die Laufzeitkosten (für das Debuggen) leisten können, können Sie valgrind mit dem massif-Tool verwenden:

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

Es ist schwer, aber sehr nützlich.

David Cournapeau
quelle
8

Ein eleganterer Weg für die Don Wakefield-Methode:

#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
quelle
7

Die vorhandenen Antworten sind besser, um den richtigen Wert zu erhalten, aber ich kann zumindest erklären, warum getrusage bei Ihnen nicht funktioniert.

Mann 2 getrusage:

Die obige Struktur wurde aus BSD 4.3 Reno übernommen. Nicht alle Felder sind unter Linux von Bedeutung. Derzeit (Linux 2.4, 2.6) werden nur die Felder ru_utime, ru_stime, ru_minflt, ru_majflt und ru_nswap verwaltet.

jmanning2k
quelle
3

Zusätzlich zu Ihrer Methode können
Sie den Befehl system ps aufrufen und die Speichernutzung aus der Ausgabe abrufen.
oder lesen Sie Informationen aus / proc / pid (siehe PIOCPSINFO-Struktur)

Bayda
quelle
PIOCPSINFO ist unter keinem Linux, das ich verwendet habe, wirklich verfügbar. Das Lesen von / proc / pid ist ziemlich häufig. Ich werde Beispielcode für Linux in einer Antwort posten ...
Don Wakefield
Ja / proc / pid-Strukturen können auf verschiedenen * nix-Plattformen unterschiedlich sein, aber wenn Sie PIOCPSINFO haben, ist das egal. Ich hatte eine Situation, in der diese Struktur in einer Solaris-Version nicht definiert war. In diesem Fall habe ich die ps-Ausgabe verwendet.
Bayda
2

Auf Ihrem System befindet sich eine Datei mit dem Namen /proc/self/statm. Das proc-Dateisystem ist ein Pseudo-Dateisystem, das eine Schnittstelle zu Kernel-Datenstrukturen bietet. Diese Datei enthält die Informationen, die Sie benötigen, in Spalten mit nur Ganzzahlen, die durch Leerzeichen getrennt sind.

Spalten-Nr.:

  1. = Gesamtprogrammgröße (VmSize in / proc / [pid] / status)

  2. = residente Satzgröße (VmRSS in / proc / [pid] / status)

Weitere Informationen finden Sie im LINK .

Jakub Krawczuk
quelle
1

Ich benutze andere Wege, um das zu tun und es klingt realistisch. Was ich tue, ist, dass ich die PID des Prozesses durch die Funktion getpid () erhalten habe und dann die Datei / proc / pid / stat verwende. Ich glaube, die 23. Spalte der Statistikdatei ist die vmsize (siehe Don-Beitrag). Sie können die vmsize aus der Datei lesen, wo immer Sie sie im Code benötigen. Wenn Sie sich fragen, wie viel ein Code-Snippet möglicherweise Speicherplatz beansprucht, können Sie diese Datei einmal vor und einmal danach lesen und sie voneinander subtrahieren.


quelle
1

Basierend auf der Lösung von Don W mit weniger Variablen.

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εδιϲ
quelle
0

Ich suchte nach einer Linux-App, um den maximal verwendeten Speicher zu messen. valgrind ist ein ausgezeichnetes Werkzeug, gab mir aber mehr Informationen als ich wollte. tstime schien das beste Werkzeug zu sein, das ich finden konnte. Es misst die "Hochwasser" -Speicherauslastung (RSS und virtuell). Siehe diese Antwort .

jtpereyda
quelle