Question

How to Measure CPU and Memory Usage from Inside a C++ Process on Windows and Linux

ccppmemorycpu

Question

I need to determine performance metrics from inside a running application, and the code must work on both Windows and Linux.

The metrics I want to access are:

  • Total virtual memory available
  • Virtual memory currently used
  • Virtual memory currently used by the current process
  • Total RAM available
  • RAM currently used
  • RAM currently used by the current process
  • Percentage of CPU currently used
  • Percentage of CPU currently used by the current process

This seems like a standard systems-programming task, but reliable information is often scattered, incomplete, outdated, or platform-specific. What is the correct way to gather these CPU and memory statistics from within a C++ application on Windows and Linux?

Short Answer

By the end of this page, you will understand how applications can inspect system and process resource usage from inside the program itself. You will learn the difference between system-wide and process-specific metrics, how CPU usage is calculated over time, how memory figures differ between virtual memory and RAM, and how to gather this information in C++ on both Windows and Linux.

Concept

System resource monitoring from inside an application means asking the operating system for information about memory and CPU usage.

There are two big ideas here:

  • System-wide metrics: how much memory or CPU the whole machine is using
  • Process-specific metrics: how much memory or CPU your program is using

A beginner-friendly way to think about this is:

  • RAM is physical memory currently available on the machine
  • Virtual memory is the larger address space that processes can use, including swapped or mapped memory
  • CPU usage is not a fixed number you can read instantly like a variable; it is usually calculated by comparing CPU time between two moments

This matters in real programming because many applications need to:

  • display health or diagnostics information
  • log performance data
  • trigger alerts when usage is too high
  • tune workloads based on current system pressure
  • help developers debug memory leaks or CPU spikes

In C++, this task is platform-dependent because Windows and Linux expose this data through different APIs and files:

  • Windows commonly uses Win32 APIs such as GlobalMemoryStatusEx, GetProcessMemoryInfo, and GetSystemTimes
  • Linux commonly reads from /proc, such as /proc/meminfo, /proc/stat, and /proc/self/status

The key lesson is that there is no single portable standard-library function in C++ for this. You usually write a small abstraction layer with one implementation for Windows and another for Linux.

Mental Model

Imagine your computer is an office building.

  • Total RAM available is the total desk space in the building.
  • RAM currently used is how many desks are occupied.
  • RAM used by your process is how much desk space your team is using.
  • Virtual memory is like all the rooms your team has reserved on paper, even if nobody is currently sitting in them.
  • CPU usage is like how busy the workers are over a period of time.

The important part is CPU usage: you cannot walk in and ask, "How busy are you right this exact instant?" You need to observe work done over a short interval.

So memory is usually a snapshot, while CPU usage is usually a rate measured over time.

Take Quiz

Syntax and Examples

Core idea

In C++, you usually create small functions such as:

struct MemoryStats {
    std::uint64_t totalPhysical;
    std::uint64_t usedPhysical;
    std::uint64_t processPhysical;
    std::uint64_t totalVirtual;
    std::uint64_t usedVirtual;
    std::uint64_t processVirtual;
};

struct CpuTimes {
    std::uint64_t idle;
    std::uint64_t total;
};

Then you provide platform-specific implementations.

Windows example: total and used memory

#include <windows.h>
#include <iostream>
#include <cstdint>

int main() {
    MEMORYSTATUSEX memInfo;
    memInfo.dwLength = sizeof(MEMORYSTATUSEX);

    if (GlobalMemoryStatusEx(&memInfo)) {
        std::uint64_t totalPhys = memInfo.ullTotalPhys;
        std::uint64_t availPhys = memInfo.ullAvailPhys;
        std::uint64_t usedPhys = totalPhys - availPhys;

        std::cout << "Total RAM: " << totalPhys << " bytes\n";
        std::cout << "Used RAM:  " << usedPhys << " bytes\n";
    }
}

What this does

  • GlobalMemoryStatusEx asks Windows for machine-wide memory information.
  • ullTotalPhys is total physical RAM.
  • ullAvailPhys is currently available RAM.
  • Used RAM is calculated as total - available.

Linux example: total and available memory

#include <iostream>
#include <fstream>
#include <string>
#include <cstdint>

int main() {
    std::ifstream file("/proc/meminfo");
    std::string key;
    std::uint64_t value;
    std::string unit;

    std::uint64_t memTotal = 0;
    std::uint64_t memAvailable = 0;

    while (file >> key >> value >> unit) {
        if (key == "MemTotal:") memTotal = value * 1024;
        if (key == "MemAvailable:") memAvailable = value * 1024;
    }

    std::cout << "Total RAM: " << memTotal << " bytes\n";
    std::cout << "Used RAM:  " << (memTotal - memAvailable) << " bytes\n";
}

What this does

  • Linux exposes memory information through /proc/meminfo.
  • Values are typically given in kilobytes.
  • MemAvailable is usually the best field for estimating usable memory.

Process memory on Linux

#include <iostream>
#include <fstream>
#include <string>

int main() {
    std::ifstream file("/proc/self/status");
    std::string line;

    while (std::getline(file, line)) {
        if (line.rfind("VmRSS:", 0) == 0 || line.rfind("VmSize:", 0) == 0) {
            std::cout << line << '\n';
        }
    }
}

This prints:

  • VmRSS: resident set size, roughly the RAM used by the process
  • VmSize: virtual memory size of the process

Important note about CPU

CPU usage usually needs two samples.

You typically:

  1. read system CPU counters
  2. read process CPU counters
  3. wait a short interval
  4. read them again
  5. compute the percentage from the difference

That is why CPU examples are often slightly more complex than memory examples.

Step by Step Execution

Example: computing Linux system CPU usage from /proc/stat

Consider this simplified line from /proc/stat:

cpu  100 20 30 400 10 0 0 0

These numbers are cumulative CPU time counters since boot.

A simple parser might use:

#include <iostream>
#include <fstream>
#include <sstream>
#include <string>
#include <thread>
#include <chrono>

struct CpuSnapshot {
    unsigned long long user = 0;
    unsigned long long nice = 0;
    unsigned long long system = 0;
    unsigned long long idle = 0;
    unsigned long long iowait = 0;
    unsigned long long irq = 0;
    unsigned long long softirq = 0;
    unsigned long long steal = 0;
};

CpuSnapshot readCpu() {
    std::ifstream file("/proc/stat");
    std::string line;
    std::getline(file, line);

    std::istringstream iss(line);
    std::string cpuLabel;
    CpuSnapshot s;
    iss >> cpuLabel >> s.user >> s.nice >> s.system >> s.idle
        >> s.iowait >> s.irq >> s.softirq >> s.steal;
    return s;
}

unsigned long long total(const CpuSnapshot& s) {
    return s.user + s.nice + s.system + s.idle + s.iowait + s.irq + s.softirq + s.steal;
}

int main() {
    CpuSnapshot a = readCpu();
    std::this_thread::sleep_for(std::chrono::milliseconds(500));
    CpuSnapshot b = readCpu();

    auto totalDiff = total(b) - total(a);
    auto idleDiff = b.idle - a.idle;

    double usage = 100.0 * (totalDiff - idleDiff) / totalDiff;
    std::cout << "CPU usage: " << usage << "%\n";
}

Step-by-step

1. First snapshot

The program reads cumulative counters from /proc/stat.

Example first sample:

  • total = 560
  • idle = 400

2. Wait briefly

The program sleeps for 500 ms.

3. Second snapshot

Suppose the next sample is:

  • total = 620
  • idle = 430

4. Compute differences

  • totalDiff = 620 - 560 = 60
  • idleDiff = 430 - 400 = 30

5. Compute busy time

Busy time is:

  • 60 - 30 = 30

6. Convert to percentage

  • 30 / 60 * 100 = 50%

So CPU usage during that half-second interval was 50%.

Why this works

The counters are cumulative since boot, not instantaneous. By subtracting two readings, you measure how much CPU time was spent doing work during the interval.

Real World Use Cases

Monitoring dashboards

Applications often expose internal metrics so operators can see:

  • current memory use
  • CPU pressure
  • whether one process is consuming too many resources

Background services and daemons

A service may reduce work when:

  • free RAM is low
  • CPU usage is high
  • the current process exceeds a memory budget

Debugging and profiling

Developers log process memory and CPU usage to detect:

  • memory leaks
  • runaway loops
  • unexpected spikes after a deployment

Desktop applications

A GUI app may show a diagnostics panel with:

  • system RAM usage
  • app memory usage
  • app CPU percentage

Batch processing tools

A data-processing program may periodically report:

  • how much RAM it is using
  • whether it is saturating CPU
  • whether the system is under heavy load

Autoscaling and self-throttling

Server software can make decisions based on current machine state, for example:

  • reduce worker count if RAM is almost full
  • delay heavy tasks if CPU is already near 100%
Take Quiz

Real Codebase Usage

In real projects, developers usually do not scatter operating-system calls all over the codebase. Instead, they wrap resource monitoring behind a small interface.

Common pattern: platform abstraction

struct SystemStats {
    std::uint64_t totalRam;
    std::uint64_t usedRam;
    double cpuPercent;
};

struct ProcessStats {
    std::uint64_t rss;
    std::uint64_t virtualSize;
    double cpuPercent;
};

class ResourceMonitor {
public:
    SystemStats getSystemStats();
    ProcessStats getProcessStats();
};

Then you implement:

  • resource_monitor_windows.cpp
  • resource_monitor_linux.cpp

Guard clauses and validation

Real code checks whether the OS call succeeded before using values.

if (!GlobalMemoryStatusEx(&memInfo)) {
    throw std::runtime_error("Failed to read memory status");
}

Sampling for CPU

CPU percentages are usually updated by a timer thread or metrics loop.

while (running) {
    sampleCpu();
    std::this_thread::sleep_for(std::chrono::seconds(1));
}

Logging and observability

Developers often transform raw numbers into metrics systems:

  • logs
  • Prometheus exporters
  • health endpoints
  • debug pages

Distinguishing RSS vs virtual size

In production systems, RSS is usually more useful for real memory pressure, while virtual size can be misleading because reserved address space does not always mean physical memory is in use.

Error handling

On Linux, /proc might not be available in unusual environments. On Windows, certain APIs can fail due to permissions or unsupported environments. Real code should fall back gracefully or return partial results.

Common Mistakes

1. Treating virtual memory as the same as RAM

These are not the same.

  • Virtual memory: address space reserved or mapped by a process
  • RAM: physical memory actually resident in memory

A process can have large virtual memory usage without using that much RAM.

2. Expecting CPU usage from a single read

This is one of the most common mistakes.

Broken idea:

// Incorrect concept: one snapshot is not enough for CPU percentage
double cpu = readCpuCounter();

Why it is wrong:

  • CPU counters are cumulative totals
  • you need two samples and a time interval

3. Using the wrong Linux memory field

Beginners often use fields that do not mean what they think.

For example:

  • VmSize is virtual memory size
  • VmRSS is resident memory
  • MemFree alone is often not the best estimate of available memory
  • MemAvailable is usually more useful for modern Linux systems

4. Forgetting unit conversions

Linux /proc files often use kilobytes, while Windows APIs often return bytes.

Broken example:

std::uint64_t bytes = value; // wrong if value came from /proc/meminfo in kB

Correct:

std::uint64_t bytes = value * 1024;

5. Ignoring multi-core CPU behavior

A process can use more than one core.

Depending on the platform and formula:

  • 100% may mean one full core
  • values may scale across all cores
  • you may need to normalize by CPU count depending on your desired output

6. Assuming process memory numbers are exact

Metrics like RSS and virtual size are useful, but they are still OS-reported views of memory usage. Shared pages, memory-mapped files, and allocator behavior can make interpretation more subtle.

7. Not handling API failure

Broken example:

MEMORYSTATUSEX memInfo;
GlobalMemoryStatusEx(&memInfo); // missing initialization and no error check

Correct:

MEMORYSTATUSEX memInfo;
memInfo.dwLength = sizeof(MEMORYSTATUSEX);
if (!GlobalMemoryStatusEx(&memInfo)) {
    // handle error
}

Comparisons

ConceptWhat it representsBest use
Total RAMPhysical memory installed/usableMachine capacity
Used RAMPhysical memory currently in useSystem pressure
Process RSSPhysical memory used by your processReal process memory footprint
Process virtual memoryReserved/mapped address spaceUnderstanding mappings or allocation patterns
System CPU usageHow busy the whole machine isLoad monitoring
Process CPU usageHow much CPU your program usesProfiling your app

RSS vs Virtual Memory

MetricMeaningCan be misleading?
RSSResident physical memoryLess misleading for memory pressure
Virtual sizeTotal mapped/reserved address spaceYes, often much larger than real RAM use

Windows vs Linux data sources

PlatformMemory sourceCPU source
WindowsGlobalMemoryStatusEx, GetProcessMemoryInfoGetSystemTimes, GetProcessTimes
Linux/proc/meminfo, /proc/self/status/proc/stat, /proc/self/stat

Instant value vs sampled value

MetricSnapshot or sample?
RAM usageUsually snapshot
Virtual memory usageUsually snapshot
CPU percentageUsually sampled over time
Take Quiz

Cheat Sheet

Quick reference

System memory

Windows

  • Use GlobalMemoryStatusEx
  • ullTotalPhys = total RAM
  • ullAvailPhys = available RAM
  • ullTotalPageFile = total virtual memory/page file related value
  • ullAvailPageFile = available virtual memory/page file related value

Linux

  • Read /proc/meminfo
  • MemTotal = total RAM
  • MemAvailable = available RAM
  • Used RAM ≈ MemTotal - MemAvailable

Process memory

Windows

  • Use GetProcessMemoryInfo
  • WorkingSetSize ≈ RAM used by process
  • PagefileUsage often used as process virtual/private usage indicator

Linux

  • Read /proc/self/status
  • VmRSS = RAM used by current process
  • VmSize = virtual memory used by current process

CPU usage

Windows

  • System CPU: GetSystemTimes
  • Process CPU: GetProcessTimes
  • Take two snapshots and compute differences

Linux

  • System CPU: /proc/stat
  • Process CPU: /proc/self/stat
  • Take two snapshots and compute differences

Rules to remember

  • Memory is usually a snapshot.
  • CPU percentage needs two samples.
  • Linux /proc values are often in kB.
  • RSS is usually better than virtual size for real memory footprint.
  • Normalize process CPU carefully if you want per-core or total-machine percentages.

Simple formulas

used_ram = total_ram - available_ram
cpu_percent = (busy_delta / total_delta) * 100

For system CPU on Linux:

busy_delta = total_delta - idle_delta

FAQ

How do I get CPU usage of my current process in C++?

Use platform-specific APIs and compare two snapshots over time. On Windows, use GetProcessTimes. On Linux, read /proc/self/stat and compute the delta.

How do I get RAM usage of my process on Linux?

Read /proc/self/status and look for VmRSS for resident memory and VmSize for virtual memory.

Is virtual memory the same as physical memory?

No. Virtual memory is address space reserved or mapped by a process. Physical memory is actual RAM currently in use.

Why can process CPU usage be above 100%?

On multi-core systems, a process can use more than one core. Depending on how you report it, usage may exceed 100%.

What is the best memory metric for real usage?

For process memory, RSS is usually the most practical metric. For system memory, MemAvailable is often better than MemFree on Linux.

Can I do this with only the C++ standard library?

No. The C++ standard library does not provide portable APIs for system CPU and memory statistics. You need OS-specific code.

Is /proc always available on Linux?

Usually yes on standard Linux systems, but not in every environment. Some containers, restricted systems, or non-Linux Unix systems may differ.

Take Quiz

Mini Project

Description

Build a small cross-platform C++ resource monitor that prints basic system and process memory information and demonstrates the sampling idea needed for CPU usage. This project is useful because it mirrors how real applications collect diagnostics for logs, health pages, or performance dashboards.

Goal

Create a console program that reports total RAM, used RAM, and memory used by the current process, using separate implementations for Windows and Linux.

Requirements

  • Create a MemoryStats struct to hold system and process memory values.
  • Implement one code path for Windows and one for Linux using preprocessor checks.
  • On Windows, use GlobalMemoryStatusEx and GetProcessMemoryInfo.
  • On Linux, read /proc/meminfo and /proc/self/status.
  • Print all values in bytes and also in megabytes for readability.
Take Quiz

Keep learning

Related questions

View more