如何使用 C + + 获得运行时的内存使用情况?

我需要获取程序运行时的 mem 使用情况 VIRT 和 RES 并显示它们。

我到目前为止所做的努力:

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

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


ret=getrusage(who,&usage);


cout<<usage.ru_maxrss;

但我总是得到0。

182719 次浏览

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"

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 )

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.

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

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.

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.

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

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.

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

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.

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.