98

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.

jww
  • 97,681
  • 90
  • 411
  • 885
  • 3
    This is system dependent -- it appears your system doesn't support reporting maxrss via getrusage -- can you tell us what distribution you're using? – tvanfosson Mar 21 '09 at 15:26
  • 1
    https://stackoverflow.com/questions/63166/how-to-determine-cpu-and-memory-consumption-from-inside-a-process – DragonLord Mar 01 '21 at 02:02

11 Answers11

84

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;
}
Community
  • 1
  • 1
Don Wakefield
  • 8,693
  • 3
  • 36
  • 54
  • 1
    do you have any guarantees about /proc/self/stat structure under different *nix platforms? ...I'm not sure, but if yes - it will nice. – bayda Mar 22 '09 at 18:55
  • 1
    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. – Don Wakefield Mar 22 '09 at 19:03
  • 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). – stsquad Apr 10 '09 at 03:49
  • 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? – a_river_in_canada Nov 29 '17 at 18:18
  • '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... – Don Wakefield Nov 29 '17 at 18:26
  • 2
    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. – Jesse Chisholm Jul 18 '18 at 19:36
61

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.

JBL
  • 12,588
  • 4
  • 53
  • 84
oblitum
  • 11,380
  • 6
  • 54
  • 120
  • 2
    had better add `#pragma comment(lib, "psapi.lib")` to the `#if defined(_WIN32)` scope. – Bloodmoon Jul 23 '13 at 01:51
  • 2
    @Bloodmon what if someone is using windows but not a microsoft compiler? That pragma would make compiler fail. – Adrian Apr 30 '19 at 14:00
  • This code uses rusage::ru_maxrss from getrusage, which the OP reported as not working for her. – facetus Mar 26 '20 at 18:09
22

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"

Paul de Vrieze
  • 4,888
  • 1
  • 24
  • 29
  • 1
    Except neither field is available in Linux. – jmanning2k Aug 03 '09 at 19:05
  • 2
    This is incorrect. maxrss is the peak memory usage of the process, not the maximum available -- that would be getrlimit(RLIMIT_DATA, &rl). – jmanning2k Aug 03 '09 at 19:16
  • 3
    Correct linker is: -lprocps – Sembiance Feb 24 '15 at 18:14
  • 2
    The `#include ` 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. – Allan Stokes Dec 04 '10 at 08:56
  • 1
    Works great, this one should be the accepted answer! – Pekov Mar 22 '18 at 11:17
12

A more elegant way for Don Wakefield method:

#include <unistd.h>
#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;
}
Ted Lyngmo
  • 93,841
  • 5
  • 60
  • 108
Qsiris
  • 1,143
  • 1
  • 13
  • 27
9

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.

David Cournapeau
  • 78,318
  • 8
  • 63
  • 70
7

The existing answers are better for how to get the correct value, but I can at least explain why getrusage isn't working for you.

man 2 getrusage:

The above struct [rusage] was taken from BSD 4.3 Reno. Not all fields are meaningful under Linux. Right now (Linux 2.4, 2.6) only the fields ru_utime, ru_stime, ru_minflt, ru_majflt, and ru_nswap are maintained.

jmanning2k
  • 9,297
  • 4
  • 31
  • 23
3

Based on Don W's solution, with fewer 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εδιϲ
  • 2,790
  • 3
  • 33
  • 54
3

in additional to your way
you could call system ps command and get memory usage from it output.
or read info from /proc/pid ( see PIOCPSINFO struct )

bayda
  • 13,365
  • 8
  • 39
  • 48
  • 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... – Don Wakefield Mar 22 '09 at 18:11
  • 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 Mar 22 '09 at 18:53
2

On your system there is a file named /proc/self/statm. The proc filesystem is a pseudo-filesystem which provides an interface to kernel data structures. This file contains the information you need in columns with only integers that are space separated.

Column no.:

  1. = total program size (VmSize in /proc/[pid]/status)

  2. = resident set size (VmRSS in /proc/[pid]/status)

For more info see the LINK.

ZF007
  • 3,708
  • 8
  • 29
  • 48
1

I am using other way to do that and it sounds realistic. What I do is i got the PID of the process by getpid() function and then I use /proc/pid/stat file. I believe the 23rd column of the stat file is the vmsize (look at the Don post). You may read the vmsize from the file wherever you need in the code. In case you wonder how much a snippet of a code may use memory, you may read that file once before that snippet and once after and you can subtract them from each other.

0

I was looking for a Linux app to measure maximum memory used. valgrind is an excellent tool, but was giving me more information than I wanted. tstime seemed to be the best tool I could find. It measures "highwater" memory usage (RSS and virtual). See this answer.

Community
  • 1
  • 1
jtpereyda
  • 6,987
  • 10
  • 51
  • 80