Memory usage of current process in C
Asked Answered
M

7

31

I need to get the memory usage of the current process in C. Can someone offer a code sample of how to do this on a Linux platform?

I'm aware of the cat /proc/<your pid>/status method of getting memory usage, but I have no idea how to capture that in C.

BTW, it's for a PHP extension I'm modifying (granted, I'm a C newbie). If there are shortcuts available within the PHP extension API, that would be even more helpful.

Marrin answered 13/10, 2009 at 5:53 Comment(0)
R
30

You can always just open the 'files' in the /proc system as you would a regular file (using the 'self' symlink so you don't have to look up your own pid):

FILE* status = fopen( "/proc/self/status", "r" );

Of course, you now have to parse the file to pick out the information you need.

Ramshackle answered 13/10, 2009 at 6:17 Comment(3)
One may also be tempted to parse /proc/self/stat which contains just numbers without labels, and according to man proc is used by ps. Or statm which is a stat subset for memory: https://mcmap.net/q/25542/-memory-usage-of-current-process-in-c Matthieu mentions that all those may be wrong for huge pages though: #1558902 I have to test it out.Marlee
I use system("cat /proc/self/status | egrep 'VmSize|VmRSS'"); to get, but it's different from what fopen reads. Don't know why.Omnivorous
@LewisChan Because your /proc/self is referring to cat. Use egrep '...' /proc/self/status to get the memory usage of egrep instead. :) More seriously, you have to substitute your PID for self if you want to fork out to a helper process.Weekend
F
32

The getrusage library function returns a structure containing a whole lot of data about the current process, including these:

long   ru_ixrss;         /* integral shared memory size */
long   ru_idrss;         /* integral unshared data size */
long   ru_isrss;         /* integral unshared stack size */

However, the most up-to-date linux documentation says about these 3 fields

(unmaintained) This field is currently unused on Linux

which the manual then defines as:

Not all fields are completed; unmaintained fields are set to zero by the kernel. (The unmaintained fields are provided for compatibility with other systems, and because they may one day be supported on Linux.)

See getrusage(2)

Fumy answered 13/10, 2009 at 5:58 Comment(2)
Unfortunately the ru_idrss and ru_isrss data isn't availabe to my kernel (Ubuntu Hardy): linux.die.net/man/2/getrusageMarrin
Unfortunately all data is showing 0 on my kernel (Debian Wheezy)Illusionary
R
30

You can always just open the 'files' in the /proc system as you would a regular file (using the 'self' symlink so you don't have to look up your own pid):

FILE* status = fopen( "/proc/self/status", "r" );

Of course, you now have to parse the file to pick out the information you need.

Ramshackle answered 13/10, 2009 at 6:17 Comment(3)
One may also be tempted to parse /proc/self/stat which contains just numbers without labels, and according to man proc is used by ps. Or statm which is a stat subset for memory: https://mcmap.net/q/25542/-memory-usage-of-current-process-in-c Matthieu mentions that all those may be wrong for huge pages though: #1558902 I have to test it out.Marlee
I use system("cat /proc/self/status | egrep 'VmSize|VmRSS'"); to get, but it's different from what fopen reads. Don't know why.Omnivorous
@LewisChan Because your /proc/self is referring to cat. Use egrep '...' /proc/self/status to get the memory usage of egrep instead. :) More seriously, you have to substitute your PID for self if you want to fork out to a helper process.Weekend
G
18

This is a terribly ugly and non-portable way of getting the memory usage, but since getrusage()'s memory tracking is essentially useless on Linux, reading /proc/<pid>/statm is the only way I know of to get the information on Linux.

If anyone know of cleaner, or preferably more cross-Unix ways of tracking memory usage, I would be very interested in learning how.

typedef struct {
    unsigned long size,resident,share,text,lib,data,dt;
} statm_t;

void read_off_memory_status(statm_t& result)
{
  unsigned long dummy;
  const char* statm_path = "/proc/self/statm";

  FILE *f = fopen(statm_path,"r");
  if(!f){
    perror(statm_path);
    abort();
  }
  if(7 != fscanf(f,"%ld %ld %ld %ld %ld %ld %ld",
    &result.size,&result.resident,&result.share,&result.text,&result.lib,&result.data,&result.dt))
  {
    perror(statm_path);
    abort();
  }
  fclose(f);
}

From the proc(5) man-page:

   /proc/[pid]/statm
          Provides information about memory usage, measured in pages.  
          The columns are:

              size       total program size
                         (same as VmSize in /proc/[pid]/status)
              resident   resident set size
                         (same as VmRSS in /proc/[pid]/status)
              share      shared pages (from shared mappings)
              text       text (code)
              lib        library (unused in Linux 2.6)
              data       data + stack
              dt         dirty pages (unused in Linux 2.6)
Goldoni answered 27/8, 2011 at 2:50 Comment(6)
The problem with this method is the measured in pages bit. If your process uses three 4kB pages, two 2MB pages and one 1GB page, it reports that 6 pages are used. Technically correct, but utterly useless to deduce the RSS in bytes.Mcculloch
@MatthieuM. man proc also ways that "/proc/[pid]/status Provides much of the information in /proc/[pid]/stat and /proc/[pid]/statm", and that stat is used by ps, which then implies that both /proc/self/status and ps itself also share this problem, is that your understanding? Can you also cite something that shows that a single process can have pages of multiple different sizes? Thanks!Marlee
@CiroSantilli新疆改造中心996ICU六四事件: I can only cite my own experience using manual huge pages + regular pages.Mcculloch
@MatthieuM. thanks, I didn't know about mmap MAP_HUGE* :-) This is sad.Marlee
Can you use & in C? I thought that was a C++ feature, isn't it? I mean, the function should accept a statm_t *result pointer instead. Am I missing something?Bespread
&x is original C and means "the address pointing to the variable x". In C++, somewhat confusingly, the same character is used in type declarations to denote references.Goldoni
S
9

I came across this post: http://appcrawler.com/wordpress/2013/05/13/simple-example-of-tracking-memory-using-getrusage/

Simplified version:

#include <sys/resource.h>
#include <stdio.h>

int main() {
  struct rusage r_usage;
  getrusage(RUSAGE_SELF,&r_usage);
  // Print the maximum resident set size used (in kilobytes).
  printf("Memory usage: %ld kilobytes\n",r_usage.ru_maxrss);
  return 0;
}

(tested in Linux 3.13)

Strangle answered 6/7, 2015 at 8:16 Comment(2)
Unfortunately also ru_maxrss is always showing 0 on my kernel (Debian Wheezy)Illusionary
This seems to work on Linux 4.12.4 at least. Although I wonder if maybe it's actually returning kilobytes.Merger
S
8
#include <sys/resource.h>
#include <errno.h>

errno = 0;
struct rusage memory;
getrusage(RUSAGE_SELF, &memory);
if(errno == EFAULT)
    printf("Error: EFAULT\n");
else if(errno == EINVAL)
    printf("Error: EINVAL\n");
printf("Usage: %ld\n", memory.ru_ixrss);
printf("Usage: %ld\n", memory.ru_isrss);
printf("Usage: %ld\n", memory.ru_idrss);
printf("Max: %ld\n", memory.ru_maxrss);

I used this code but for some reason I get 0 all the time for all 4 printf()

Shannonshanny answered 19/12, 2009 at 19:8 Comment(2)
That's because, even in version 2.6, 10 years after POSIX.1, Linux still doesn't implement getrusage() except for a few fields. :-( Apparently, the only way to get the information is through kernel calls or reading /proc/<pid>/statm (see man 5 proc), which is completely unportable.Goldoni
Why are you using malloc for a statically sized struct?Redwood
P
8

I'm late to the party, but this might be helpful for anyone else looking for the resident and virtual (and their peak values so far) memories on linux.

It's probably pretty terrible, but it gets the job done.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>


/*
 * Measures the current (and peak) resident and virtual memories
 * usage of your linux C process, in kB
 */
void getMemory(
    int* currRealMem, int* peakRealMem,
    int* currVirtMem, int* peakVirtMem) {

    // stores each word in status file
    char buffer[1024] = "";

    // linux file contains this-process info
    FILE* file = fopen("/proc/self/status", "r");

    // read the entire file
    while (fscanf(file, " %1023s", buffer) == 1) {

        if (strcmp(buffer, "VmRSS:") == 0) {
            fscanf(file, " %d", currRealMem);
        }
        if (strcmp(buffer, "VmHWM:") == 0) {
            fscanf(file, " %d", peakRealMem);
        }
        if (strcmp(buffer, "VmSize:") == 0) {
            fscanf(file, " %d", currVirtMem);
        }
        if (strcmp(buffer, "VmPeak:") == 0) {
            fscanf(file, " %d", peakVirtMem);
        }
    }
    fclose(file);
}
Phillipp answered 28/11, 2017 at 12:2 Comment(5)
Caution; I don't handle when file doesn't existPhillipp
shouldn't int * be int and fscanf args be e.g. &currRealMem instead of currRealMem???Herniotomy
@Herniotomy No, this function "returns" by modifying the referenced primitives. You want to pass references of the caller primitives to this function. E.g. int a, b, c, d; getMemory(&a, &b, &c, &d);Phillipp
my bad, misread those int*s as being local vars rather than function args.Herniotomy
Note that fopen of /proc/self/status can fail intermittently so checkTerse
P
0

The above struct was taken from 4.3BSD Reno. Not all fields are mean- ingful under Linux. In linux 2.4 only the fields ru_utime, ru_stime, ru_minflt, and ru_majflt are maintained. Since Linux 2.6, ru_nvcsw and ru_nivcsw are also maintained.

http://www.atarininja.org/index.py/tags/code

Precision answered 19/4, 2010 at 19:16 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.