How do you determine the amount of Linux system RAM in C++?
Asked Answered
G

4

33

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?

Garrek answered 8/12, 2008 at 15:38 Comment(0)
A
84

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
}
Anosmia answered 8/12, 2008 at 16:18 Comment(3)
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.Carrell
This Linux kernel commit message 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."Carrell
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 unix.stackexchange.com/questions/500089/… )Ascham
A
6

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;
}
Annulment answered 8/12, 2008 at 16:17 Comment(1)
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. :)Garrek
H
3

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

Humanity answered 8/12, 2008 at 17:20 Comment(0)
A
1

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

Anthraquinone answered 8/12, 2008 at 16:3 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.