Version 1.0.0 · Changelog · License: MIT
A lightweight C++ library that reads /proc/<pid>/maps (and optionally /proc/<pid>/smaps) and outputs structured JSON snapshots of a process's memory regions.
- Linux (uses
/procfilesystem) - GCC 10+ or any compiler with C++20 support
- CMake 3.16+
# Clone / navigate to the project
cd memc
# Configure and build
cmake -B build -S . -DCMAKE_BUILD_TYPE=Release
cmake --build build -j$(nproc)The binary is produced at ./build/memc.
# Install to /usr/local (headers, static lib, CLI binary, and CMake package config)
sudo cmake --install build
# Or install to a custom prefix
cmake --install build --prefix /opt/memcAfter installing, downstream CMake projects can use:
find_package(memc 1.0 REQUIRED)
target_link_libraries(your_target PRIVATE memc::memc_lib)memc <pid> [options]
memc --all [options]
| Flag | Description | Default |
|---|---|---|
--all |
Snapshot ALL processes on the system | off |
--smaps |
Enable detailed smaps data (RSS, PSS, swap, etc.) | off |
--output <file> |
Write JSON to a file instead of stdout | stdout |
--interval <ms> |
Sampling interval in milliseconds | 1000 |
--count <n> |
Number of samples (0 = continuous until Ctrl+C) | 1 |
--compact |
Output compact JSON instead of pretty-printed | off |
--skip-kernel |
Skip kernel threads with no user-space memory | off |
--version |
Show version information | — |
--help |
Show help message | — |
# Single snapshot of a process
./build/memc 1234
# Snapshot with detailed memory info (RSS, PSS, swap, shared/private pages)
./build/memc 1234 --smaps
# Monitor the current shell
./build/memc $$
# ── System-wide snapshots ──────────────────────────────
# Snapshot ALL processes with smaps detail
./build/memc --all --smaps
# Save system-wide snapshot to a file
./build/memc --all --smaps --output system.json
# Compact system-wide snapshot (smaller file)
./build/memc --all --smaps --compact --output system.json
# ── Periodic sampling ─────────────────────────────────
# Continuous sampling every 500ms (Ctrl+C to stop)
./build/memc 1234 --count 0 --interval 500
# Take 5 samples, 2 seconds apart, compact JSON
./build/memc 1234 --count 5 --interval 2000 --compact
# Pipe to jq for quick filtering
./build/memc $$ --smaps | jq '.regions[] | select(.type == "heap")'All output goes to stdout (status messages go to stderr), or to a file with --output.
{
"pid": 1234,
"timestamp_ms": 1771011124506,
"total_rss_kb": 4820,
"total_vsize_kb": 233592,
"region_count": 29,
"regions": [
{
"start": "0x5583794a9000",
"end": "0x5583795ac000",
"type": "code",
"perm": "r-xp",
"size_kb": 1036,
"pathname": "/usr/bin/bash"
},
{
"start": "0x5583a7c32000",
"end": "0x5583a7dda000",
"type": "heap",
"perm": "rw-p",
"size_kb": 1696,
"pathname": "[heap]",
"rss_kb": 132,
"pss_kb": 132,
"shared_clean_kb": 0,
"shared_dirty_kb": 0,
"private_clean_kb": 0,
"private_dirty_kb": 132,
"swap_kb": 0
}
]
}{
"timestamp_ms": 1771011727828,
"process_count": 457,
"skipped": 60,
"processes": [
{
"pid": 1234,
"name": "bash",
"snapshot": {
"pid": 1234,
"region_count": 29,
"regions": [ ... ],
"total_rss_kb": 4820,
"total_vsize_kb": 233592
}
}
]
}Note: The
rss_kb,pss_kb,shared_*,private_*, andswap_kbfields only appear when--smapsis enabled. Theskippedfield in--allmode shows processes that couldn't be read (usually due to permissions).
| Type | Description |
|---|---|
heap |
Process heap ([heap]) |
stack |
Thread/process stack ([stack]) |
code |
Executable text segments |
shared_lib |
Shared library mappings (.so) |
mapped_file |
Memory-mapped files |
anonymous |
Anonymous mappings (no backing file) |
vdso |
Virtual Dynamic Shared Object |
vvar |
Kernel vvar page |
vsyscall |
Legacy vsyscall page |
unknown |
Unclassified mapping |
This project uses clang-format to enforce a consistent code style across all C/C++ source and header files. The configuration is defined in the .clang-format file at the project root.
# Format a single file
clang-format -i src/collector.cpp
# Format all project source files (excludes third_party/)
find . -type f \( -name '*.cpp' -o -name '*.h' \) ! -path './third_party/*' | xargs clang-format -i
# Dry-run (check without modifying)
find . -type f \( -name '*.cpp' -o -name '*.h' \) ! -path './third_party/*' | xargs clang-format --dry-run -WerrorNote: The
third_party/directory (e.g.nlohmann/json.hpp) is intentionally excluded from formatting.
You can also use memc as a library in your own C++ project:
#include <memc/collector.h>
#include <memc/version.h>
#include <iostream>
int main() {
std::cout << "memc v" << MEMC_VERSION_STRING << "\n";
pid_t target_pid = 1234;
// Single snapshot
memc::DataCollector collector(target_pid, {.use_smaps = true});
auto snapshot = collector.collect_once();
if (snapshot) {
std::cout << collector.to_json(*snapshot) << std::endl;
}
// Periodic sampling with callback
memc::DataCollector sampler(target_pid, {
.use_smaps = true,
.interval_ms = 500,
.max_snapshots = 100 // ring buffer of last 100
});
sampler.on_snapshot([](const memc::ProcessSnapshot& snap) {
std::cout << "RSS: " << snap.total_rss_kb() << " KB\n";
});
sampler.start_sampling();
// ... do work ...
sampler.stop_sampling();
}Link against memc_lib and pthread in your CMake:
target_link_libraries(your_target PRIVATE memc_lib)Or, if you installed memc system-wide:
find_package(memc 1.0 REQUIRED)
target_link_libraries(your_target PRIVATE memc::memc_lib)When running ./build/memc --all, some processes will appear in the skipped_processes array. These are typically root-owned system services (systemd, dockerd, NetworkManager, etc.) whose /proc/<pid>/maps cannot be read by a regular user.
To collect all processes including these, run with elevated privileges:
sudo ./build/memc --all --smaps --output full_system.jsonYou'll notice many processes (like kworker, ksoftirqd, migration, rcu_preempt, etc.) show region_count: 0 with an empty regions array. This is expected — these are kernel threads that run entirely in kernel space and have no user-space virtual memory mappings. Their /proc/<pid>/maps is legitimately empty.
| Access | Requirement |
|---|---|
/proc/<pid>/maps (own processes) |
No special permissions needed |
/proc/<pid>/maps (other users' processes) |
Root or CAP_SYS_PTRACE |
/proc/<pid>/smaps (own processes) |
No special permissions needed |
/proc/<pid>/smaps (other users' processes) |
Root or CAP_SYS_PTRACE |
MIT © 2026 Huzaifa