How to get memory usage at runtime using C++?

172,419

Solution 1

On Linux, I've never found an ioctl() solution. For our applications, we coded a general utility routine based on reading files in /proc/pid. There are a number of these files which give differing results. Here's the one we settled on (the question was tagged C++, and we handled I/O using C++ constructs, but it should be easily adaptable to C i/o routines if you need to):

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

Solution 2

David Robert Nadeau has put a good self contained multi-platform C function to get the process resident set size (physical memory use) in his website:

/*
 * 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( );

For more discussion, check the web site, it also provides a function to get the physical memory size of a system.

Solution 3

Old:

maxrss states the maximum available memory for the process. 0 means that no limit is put upon the process. What you probably want is unshared data usage ru_idrss.

New: It seems that the above does not actually work, as the kernel does not fill most of the values. What does work is to get the information from proc. Instead of parsing it oneself though, it is easier to use libproc (part of procps) as follows:

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

Compile with "gcc -o getrusage getrusage.c -lproc"

Solution 4

A more elegant way for Don Wakefield method:

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

Solution 5

On linux, if you can afford the run time cost (for debugging), you can use valgrind with the massif tool:

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

It is heavy weight, but very useful.

Share:
172,419
Admin
Author by

Admin

Updated on December 31, 2020

Comments

  • Admin
    Admin over 3 years

    I need to get the mem usage VIRT and RES at run time of my program and display them.

    What i tried so far:

    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;
    

    but i always get 0.

  • Don Wakefield
    Don Wakefield about 15 years
    PIOCPSINFO isn't really available on any Linux I've used. Reading from /proc/pid is pretty common. I'll post example code for Linux in an answer...
  • bayda
    bayda about 15 years
    yes /proc/pid structures couls be different in different *nix platforms, but if you have PIOCPSINFO it is no matter. I've had situation when this structure was not defined on some solaris version.. I've used ps output in this case.
  • bayda
    bayda about 15 years
    do you have any guarantees about /proc/self/stat structure under different *nix platforms? ...I'm not sure, but if yes - it will nice.
  • Don Wakefield
    Don Wakefield about 15 years
    Well, over the years I've mostly used Solaris, HP-UX and Linux. /proc/self/stat seems to be a Linux-ism. The original version of the program above had #if blocks for Solaris since it differed.
  • user1750701
    user1750701 about 15 years
    I'm assuming the OP only cares about Linux based on the question tagging. Reading /proc will be about as good as you get. On Solaris you can also get the information on all sorts of stuff via kstat (although it often replicates what you can get via other means).
  • Oliver Turner
    Oliver Turner almost 15 years
    Except neither field is available in Linux.
  • Oliver Turner
    Oliver Turner almost 15 years
    This is incorrect. maxrss is the peak memory usage of the process, not the maximum available -- that would be getrlimit(RLIMIT_DATA, &rl).
  • Allan Stokes
    Allan Stokes over 13 years
    The #include <proc/readproc.h> solution worked great for me under Ubuntu. I had to install package libproc-dev. usage.vm_data is a close enough approximation to what I needed. Your choice of memory statistic are documented here: /usr/include/proc/readproc.h The ones I tried all seem to be in bytes, not pages. I don't think my process was using 46 million pages. Comments that this solution doesn't work under Linux seem misguided.
  • Bloodmoon
    Bloodmoon almost 11 years
    had better add #pragma comment(lib, "psapi.lib") to the #if defined(_WIN32) scope.
  • Sembiance
    Sembiance about 9 years
    Correct linker is: -lprocps
  • a_river_in_canada
    a_river_in_canada over 6 years
    I'm only 10 years late to the party, but would you mind telling me why you divide vsize by 1024.0 rather than 1024?
  • Don Wakefield
    Don Wakefield over 6 years
    'river', sorry, but as you note, many years have passed. If I had any reason it is lost to time (and I failed everyone by not noting the exceptional choice in a comment). My only defense is that in this case, 1024.0 can represent 1024 without loss of precision...
  • Pekov
    Pekov about 6 years
    Works great, this one should be the accepted answer!
  • Jesse Chisholm
    Jesse Chisholm almost 6 years
    re: why 1024.0? - It does tell the compiler to convert to double FIRST and then do the divide to get the double result. The other choice: vm_usage = vsize / 1024; would do the divide first, (losing precision as @DonWakefield intimated) and then convert to double.
  • Adrian
    Adrian about 5 years
    @Bloodmon what if someone is using windows but not a microsoft compiler? That pragma would make compiler fail.
  • facetus
    facetus about 4 years
    This code uses rusage::ru_maxrss from getrusage, which the OP reported as not working for her.
  • Bensuperpc
    Bensuperpc almost 3 years
    If you have error, you can add #include <unistd.h>