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.

caf
  • 233,326
  • 40
  • 323
  • 462
scotts
  • 4,027
  • 3
  • 29
  • 26

7 Answers7

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)

Ciro Santilli OurBigBook.com
  • 347,512
  • 102
  • 1,199
  • 985
caf
  • 233,326
  • 40
  • 323
  • 462
  • 2
    Unfortunately the ru_idrss and ru_isrss data isn't availabe to my kernel (Ubuntu Hardy): http://linux.die.net/man/2/getrusage – scotts Oct 13 '09 at 17:19
  • Unfortunately all data is showing 0 on my kernel (Debian Wheezy) – Achim Mar 01 '17 at 12:30
28

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.

CB Bailey
  • 755,051
  • 104
  • 632
  • 656
  • 1
    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://stackoverflow.com/a/7212248/895245 Matthieu mentions that all those may be wrong for huge pages though: https://stackoverflow.com/questions/1558402/memory-usage-of-current-process-in-c/7212248?noredirect=1#comment101785466_7212248 I have to test it out. – Ciro Santilli OurBigBook.com Aug 27 '19 at 07:00
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)
Olaf Dietsche
  • 72,253
  • 8
  • 102
  • 198
James
  • 404
  • 4
  • 9
  • 3
    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. – Matthieu M. Nov 12 '18 at 13:25
  • @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! – Ciro Santilli OurBigBook.com Aug 26 '19 at 22:08
  • 1
    @CiroSantilli新疆改造中心996ICU六四事件: I can only cite my own experience using manual huge pages + regular pages. – Matthieu M. Aug 27 '19 at 06:32
  • @MatthieuM. thanks, I didn't know about `mmap` `MAP_HUGE*` :-) This is sad. – Ciro Santilli OurBigBook.com Aug 27 '19 at 06:58
  • 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? – SRG Feb 10 '20 at 16:46
  • &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. – James Feb 11 '20 at 17:27
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)

Amos
  • 3,238
  • 4
  • 19
  • 41
lepe
  • 24,677
  • 9
  • 99
  • 108
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()

Jack G
  • 4,553
  • 2
  • 41
  • 50
Jeff
  • 105
  • 1
  • 1
  • 9
    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//statm (see man 5 proc), which is completely unportable. – James Aug 27 '11 at 02:39
  • 7
    Why are you using malloc for a statically sized struct? – Not a Name Nov 27 '12 at 03:05
7

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);
}
Anti Earth
  • 4,671
  • 13
  • 52
  • 83
  • Caution; I don't handle when `file` doesn't exist – Anti Earth Feb 05 '18 at 16:13
  • shouldn't ```int *``` be ```int``` and fscanf args be e.g. ```&currRealMem``` instead of ```currRealMem```??? – mwag Nov 29 '19 at 20:40
  • @mwag 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);` – Anti Earth Nov 30 '19 at 01:11
  • my bad, misread those ```int*```s as being local vars rather than function args. – mwag Nov 30 '19 at 02:03
  • Note that fopen of /proc/self/status can fail intermittently so check – GroovyDotCom Jun 29 '21 at 12:22
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