32

I just wrote the following C++ function to programmatically determine how much RAM a system has installed. It works, but it seems to me that there should be a simpler way to do this. Am I missing something?

getRAM()
{
    FILE* stream = popen("head -n1 /proc/meminfo", "r");
    std::ostringstream output;
    int bufsize = 128;

    while( !feof(stream) && !ferror(stream))
    {
        char buf[bufsize];
        int bytesRead = fread(buf, 1, bufsize, stream);
        output.write(buf, bytesRead);
    }
    std::string result = output.str();

    std::string label, ram;
    std::istringstream iss(result);
    iss >> label;
    iss >> ram;

    return ram;
}

First, I'm using popen("head -n1 /proc/meminfo") to get the first line of the meminfo file from the system. The output of that command looks like

MemTotal: 775280 kB

Once I've got that output in an istringstream, it's simple to tokenize it to get at the information I want. Is there a simpler way to read in the output of this command? Is there a standard C++ library call to read in the amount of system RAM?

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Bill the Lizard
  • 398,270
  • 210
  • 566
  • 880

4 Answers4

82

On Linux, you can use the function sysinfo which sets values in the following struct:

   #include <sys/sysinfo.h>

   int sysinfo(struct sysinfo *info);

   struct sysinfo {
       long uptime;             /* Seconds since boot */
       unsigned long loads[3];  /* 1, 5, and 15 minute load averages */
       unsigned long totalram;  /* Total usable main memory size */
       unsigned long freeram;   /* Available memory size */
       unsigned long sharedram; /* Amount of shared memory */
       unsigned long bufferram; /* Memory used by buffers */
       unsigned long totalswap; /* Total swap space size */
       unsigned long freeswap;  /* swap space still available */
       unsigned short procs;    /* Number of current processes */
       unsigned long totalhigh; /* Total high memory size */
       unsigned long freehigh;  /* Available high memory size */
       unsigned int mem_unit;   /* Memory unit size in bytes */
       char _f[20-2*sizeof(long)-sizeof(int)]; /* Padding for libc5 */
   };

If you want to do it solely using functions of C++ (I would stick to sysinfo), I recommend taking a C++ approach using std::ifstream and std::string:

unsigned long get_mem_total() {
    std::string token;
    std::ifstream file("/proc/meminfo");
    while(file >> token) {
        if(token == "MemTotal:") {
            unsigned long mem;
            if(file >> mem) {
                return mem;
            } else {
                return 0;
            }
        }
        // Ignore the rest of the line
        file.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
    }
    return 0; // Nothing found
}
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Johannes Schaub - litb
  • 496,577
  • 130
  • 894
  • 1,212
  • 13
    It is worth noting that `freeram` in `sysinfo` is not what most people would call "free RAM". `freeram` _excludes_ memory used by cached filesystem metadata ("buffers") and contents ("cache"). Both of these can be a significant portion of RAM but are freed by the OS when programs need that memory. `sysinfo` does contain size used by buffers (`sysinfo.bufferram`), but not cache. The best option is to use the `MemAvailable` (as opposed to `MemFree`) entry in `/proc/meminfo` instead. – Vicky Chijwani Jul 29 '16 at 11:01
  • 10
    This [Linux kernel commit message](https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/commit/?id=34e431b0ae398fc54ea69ff85ec700722c9da773) explains there are more nuances. It says: "Many programs check /proc/meminfo to estimate how much free memory is available. They generally do this by adding up "free" and "cached", which was fine ten years ago, but is **pretty much guaranteed to be wrong today**." – Vicky Chijwani Jul 29 '16 at 11:08
  • The amount of memory shown in `/proc/meminfo` might not match the amount of RAM **physically** installed. eg. if the machine has 16GB of RAM modules installed and is booted normally, `meminfo` shows 16GB. However, if the machine is booted with the `mem=4GB` kernel parameter, `meminfo` shows 4GB while the actual RAM is indeed 16GB. Sometimes that matters (read the comments in https://unix.stackexchange.com/questions/500089/very-slow-write-speed-to-raid-with-32-bit-4-4-kernel-if-machine-has-more-than-4g?noredirect=1#comment922199_500089 ) – Danny Mar 29 '19 at 10:15
4

There isn't any need to use popen(). You can just read the file yourself.

Also, if their first line isn't what you're looking for, you'll fail, since head -n1 only reads the first line and then exits. I'm not sure why you're mixing C and C++ I/O like that; it's perfectly OK, but you should probably opt to go all C or all C++. I'd probably do it something like this:

int GetRamInKB(void)
{
    FILE *meminfo = fopen("/proc/meminfo", "r");
    if(meminfo == NULL)
        ... // handle error

    char line[256];
    while(fgets(line, sizeof(line), meminfo))
    {
        int ram;
        if(sscanf(line, "MemTotal: %d kB", &ram) == 1)
        {
            fclose(meminfo);
            return ram;
        }
    }

    // If we got here, then we couldn't find the proper line in the meminfo file:
    // do something appropriate like return an error code, throw an exception, etc.
    fclose(meminfo);
    return -1;
}
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Adam Rosenfield
  • 390,455
  • 97
  • 512
  • 589
  • The first line had of /proc/meminfo was the information I was after. I'm returning to C++ after many years, so I don't yet have a good sense of C vs. C++ style, but I'm working on it. Thanks. :) – Bill the Lizard Dec 08 '08 at 16:27
3

Remember /proc/meminfo is just a file. Open the file, read the first line, and close the file. Voilà!

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Charlie Martin
  • 110,348
  • 25
  • 193
  • 263
1

Even top (from procps) parses /proc/meminfo. See here.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Bombe
  • 81,643
  • 20
  • 123
  • 127