Measuring VSS And RSS
Per-process memory accounting for embedded Linux — free linux kernel development course
If you are building a free linux kernel development course style skill set, per-process memory accounting is one of the first debugging muscles you need. Every embedded board ships with a fixed, small amount of RAM, and the moment an application starts growing unexpectedly, you need fast answers to “how much memory is this process actually using?” That question has more than one correct answer, and this lecture explains why, using the two simplest metrics the kernel exposes: VSS (virtual set size) and RSS (resident set size).
Keywords covered
What You Will Learn
- What VSS and RSS actually measure, and why neither is “the” memory usage number
- How to read VSS/RSS from
/proc/<PID>/statusdirectly, without any tool - How to pull the same numbers with
psandtopon a target board - Why RSS totals across processes overestimate real memory pressure
- A small original C demo you can build and watch grow in real time
Prerequisites
You should already be comfortable with basic Linux process concepts (PID, virtual memory, paging) and have access to a Linux target — a Raspberry Pi, BeagleBone, or even a desktop VM is fine. No kernel module work is needed for this lecture.
Why One Memory Number Is Not Enough
A running process touches memory in layers. It reserves address space for its code, its stack, its heap, and any libraries it links against — that reservation is virtual and costs nothing until pages are actually touched. Only the pages the process has actually read or written get backed by physical RAM. That physical backing is what the kernel calls resident memory.
This distinction matters enormously on embedded targets. A process can reserve gigabytes of virtual address space (common with modern allocators and thread stacks) while only touching a few megabytes of real RAM. If you only look at virtual size, you will chase a “leak” that does not exist. If you only look at resident size, you may miss the fact that many processes are sharing the same physical pages — which the next lecture on USS/PSS will fix.
VSS: Virtual Set Size
VSS is the sum of every memory region mapped into a process’s address space — every entry you would see in /proc/<PID>/maps: the executable’s text and data segments, every shared library, the heap, the stack, and any anonymous mmap regions. It is reported as VSZ by ps and VIRT by top.
VSS is a weak signal for memory pressure. A 64-bit process with a large thread pool can easily show hundreds of megabytes of VSS purely from unused guard pages and reserved-but-untouched stack space, none of which occupies physical RAM.
RSS: Resident Set Size
RSS is the sum of pages from those mapped regions that are currently backed by physical memory — reported as RSS by ps and RES by top. RSS is much closer to “real” memory usage, but it has its own trap: shared libraries like libc are mapped — and resident — in every process that uses them. If you naively sum the RSS of every process on the board, you will double-count (or worse) every shared page, producing a total far higher than the physical RAM installed.
Reading Memory Straight From /proc
Before reaching for any tool, it is worth knowing that the kernel exposes this data directly. Every process has a human-readable status file:
$ cat /proc/$$/status | grep -E 'VmSize|VmRSS'
VmSize: 9124 kB
VmRSS: 3312 kB
VmSize is VSS, VmRSS is RSS, for the current shell ($$). This works identically on the smallest embedded board and the largest server — no extra package required.
Using ps And top On A Target
On boards running BusyBox, the built-in ps/top applets show very limited columns. If your rootfs includes the full procps package (Buildroot and Yocto both offer it), you get proper VSZ/RSS reporting:
$ ps -eo pid,vsz,rss,comm
PID VSZ RSS COMMAND
1 3288 1980 init
412 9124 3312 ep-memdemo
588 46512 8940 networkd
top gives the same two columns live, letting you watch RSS climb in real time — the fastest first check for a suspected leak:
$ top -b -n 1 | grep ep-memdemo
412 root 20 0 9124 3312 1024 S 0.3 0.6 0:00.41 ep-memdemo
Original Demo: Watching RSS Grow
Here is a small, original demo program — not from any textbook — that allocates memory in a loop and touches every byte, so you can watch VSS and RSS diverge and then converge in real time.
/* ep_memdemo.c - watch VSS vs RSS grow */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#define CHUNK (1024 * 1024) /* 1 MB per step */
#define STEPS 20
int main(void)
{
void *blocks[STEPS];
printf("ep_memdemo pid=%d - watch with:\n", getpid());
printf(" watch -n1 'grep -E \"VmSize|VmRSS\" /proc/%d/status'\n", getpid());
sleep(3);
for (int i = 0; i < STEPS; i++) {
blocks[i] = malloc(CHUNK);
if (!blocks[i]) {
fprintf(stderr, "allocation failed at step %d\n", i);
return 1;
}
memset(blocks[i], 0xA5, CHUNK); /* touch every page */
printf("step %2d: allocated and touched %d MB total\n", i, i + 1);
sleep(1);
}
printf("done - process will hold memory for 10s, then exit\n");
sleep(10);
return 0;
}
Build and run it, then watch /proc/<PID>/status in a second terminal:
$ gcc -Wall -O2 -o ep_memdemo ep_memdemo.c
$ ./ep_memdemo
ep_memdemo pid=4231 - watch with:
watch -n1 'grep -E "VmSize|VmRSS" /proc/4231/status'
step 0: allocated and touched 1 MB total
step 1: allocated and touched 2 MB total
...
step 19: allocated and touched 20 MB total
done - process will hold memory for 10s, then exit
Expected output in the second terminal, mid-run:
VmSize: 24680 kB
VmRSS: 21344 kB
Notice VmSize grows in step with VmRSS here, because memset() forces every allocated page to actually be touched. If you comment out the memset() call and rebuild, you will see VmSize climb identically while VmRSS stays almost flat — proof that allocation alone does not consume physical RAM until pages are written to.
VSS vs RSS At A Glance
| Metric | ps column | top column | What it really tells you |
|---|---|---|---|
| VSS | VSZ | VIRT | Total address space reserved; weak leak signal |
| RSS | RSS | RES | Physical pages resident; good first leak signal, but double-counts shared pages across processes |
Common Mistakes
- Summing RSS across all processes to estimate total memory use — this overestimates because shared library pages get counted once per process.
- Treating VSS growth as a leak — a growing thread pool alone can inflate VSS with untouched stack guard regions.
- Relying on BusyBox ps/top for serious debugging — install the full
procpspackage in your Buildroot/Yocto image for the columns shown here.
Best Practices
- Use RSS as your first, cheap signal that something is growing; confirm with USS/PSS (next lecture) before trusting the absolute number.
- Sample
/proc/<PID>/statuson a timer in CI or on-device logging for long-running embedded daemons — it costs nothing and needs no extra tooling. - When reporting memory bugs, always quote both VSS and RSS together, never one alone.
Summary And Key Takeaways
VSS tells you how much address space a process has reserved; RSS tells you how much of that is actually backed by physical RAM. Neither is the full picture on its own, and summing RSS across processes overstates real usage because of shared pages. This is exactly the gap the next lecture closes with USS and PSS, using the smem tool.
Conclusion
For anyone working through a free linux device drivers course or building embedded daemons, VSS and RSS are the first two numbers you should learn to read without any extra tooling — straight from /proc. They are fast, always available, and enough to catch the majority of obvious leaks before you need heavier tools.
FAQ
What is the difference between VSS and RSS?
VSS is total virtual address space mapped by a process; RSS is the portion of that space currently backed by physical RAM pages.
Why does RSS double-count memory across processes?
Shared libraries like libc are mapped into every process that uses them, and each process’s RSS counts those shared pages individually, even though they occupy the same physical RAM once.
Can VSS be larger than the device’s total RAM?
Yes. VSS only reflects reserved address space, which can vastly exceed physical RAM since most of it is never touched.
Does BusyBox top show RSS?
BusyBox’s minimal top/ps show very limited columns; install the full procps package for reliable VSZ/RSS reporting.
How do I check memory usage without any external tool?
Read /proc/<PID>/status and look at the VmSize and VmRSS lines — no package installation required.
Is a growing RSS always a memory leak?
Not always — caches and legitimately growing working sets also raise RSS. Confirm with sustained growth over time and cross-check with USS in the next lecture.
What tool comes next after VSS/RSS in this free linux kernel development course?
The next lecture covers USS and PSS using the smem tool, which correctly splits shared-page accounting between processes.
Continue The Free Linux Kernel Development Course
Next up: USS and PSS with smem, for accurate per-process memory accounting on shared libraries.
Next Lecture Course Index
2 Comments