Measuring Kernel Memory Usage
Lecture 2 of the Managing Memory chapter — what actually consumes kernel-space RAM, and the tools that tell you how much is left.
Table of Contents
- What You Will Learn
- Prerequisites
- What Consumes Kernel-Space Memory
- Hands-On: Reading Your Kernel’s Own Memory Map
- How Much Memory Does the Kernel Use?
- Checking Kernel Image Size
- Reading /proc/meminfo
- Hands-On: An Original Module That Reports Its Own Footprint
- Common Mistakes and Troubleshooting
- Best Practices
- Interview Questions
- Summary and Key Takeaways
- FAQ
What You Will Learn
This lecture continues our free embedded systems course and the Managing Memory chapter of our free linux device drivers course. You will learn exactly what categories of data occupy kernel-space memory, how to read the kernel’s own boot-time memory summary, how to check the static size of a kernel image with the size command, how to interpret /proc/meminfo on a live embedded board, and how to write a small original module that reports its own memory footprint.
Prerequisites
This lecture builds directly on the previous one, Understanding Kernel Virtual Memory — make sure you’re comfortable with the user space/kernel space split and the states a virtual page can be in before continuing. You’ll also need shell access to a running embedded Linux target (or QEMU) and a cross-compilation toolchain for building a kernel module.
What Consumes Kernel-Space Memory
Unlike user-space memory, which is demand-paged and can be discarded or swapped, kernel memory is committed the instant it’s allocated and stays resident until it’s explicitly freed. On a RAM-constrained embedded board, knowing exactly where that committed memory goes is the difference between a system that runs comfortably for months and one that mysteriously runs out of memory under load. Kernel-space consumers generally fall into a handful of categories:
- The kernel image itself — code and data loaded from the kernel image at boot, split into segments such as
.text(executable code),.data(initialized data), and.bss(zero-initialized data). A special.initsegment holds code only needed during boot and is freed once initialization completes. - Slab allocations — small, frequently-used kernel data structures allocated through the slab allocator, most visibly via
kmalloc(). These come from the kernel’s general-purpose lowmem region. vmalloc()allocations — larger chunks of virtually-contiguous memory that don’t need to be physically contiguous, used when a single large buffer can’t be satisfied efficiently by the slab/buddy allocator.- Device register and MMIO mappings — drivers mapping hardware registers into kernel address space, visible today through
/proc/iomem. These occupy virtual address space but, since they point at memory outside main system RAM, they don’t consume real RAM the way ordinary allocations do. - Loaded kernel modules — the code and data of every
.kofile you’ve inserted withinsmodormodprobe. - Miscellaneous low-level allocations — early boot-time reservations and other allocations that aren’t individually tracked by any of the above categories.
Hands-On: Reading Your Kernel’s Own Memory Map
Most architectures print a summary of the virtual memory layout to the kernel log during boot. Rather than quoting any particular board’s numbers from a book, go find your own:
$ dmesg | grep -A 10 -i "memory:"
On a typical 32-bit ARM embedded board you’ll see a breakdown similar in spirit to this (values are illustrative — yours will differ by board, kernel configuration, and how much RAM is actually populated):
Memory: 254972K/262144K available (8192K kernel code, 512K rwdata,
2048K rodata, 1024K init, 256K bss, 7172K reserved)
Virtual kernel memory layout:
vector : 0xffff0000 - 0xffff1000 ( 4 kB)
vmalloc : 0xe0800000 - 0xff000000 ( 488 MB)
lowmem : 0xc0000000 - 0xe0000000 ( 512 MB)
modules : 0xbf000000 - 0xc0000000 ( 16 MB)
On 64-bit ARM64/x86_64 targets, look instead for the early boot memory report and, once the system is up, /proc/iomem for a full tree of physical memory reservations — the segmented layout above is a 32-bit-era view, but the underlying categories (kernel image, vmalloc area, module space) still apply conceptually.
How Much Memory Does the Kernel Use?
There isn’t a single number that fully answers this question, but two tools together get you most of the way there.
Checking Kernel Image Size
The static footprint of the kernel image — before it makes a single dynamic allocation — can be checked with the standard size utility from your cross-toolchain, run against the uncompressed kernel ELF image:
$ aarch64-linux-gnu-size vmlinux
text data bss dec hex filename
9871232 842176 8931840 19645248 12b5c00 vmlinux
If this figure looks unexpectedly large relative to your board’s total RAM, that’s your cue to revisit the kernel configuration and strip out subsystems, drivers, and filesystems you don’t actually need — every enabled CONFIG_* option that builds into the kernel proper adds to this static footprint.
Key Point
The size command only tells you the kernel image’s static footprint. It says nothing about slab allocations, vmalloc usage, or module memory consumed after boot — for that, you need /proc/meminfo.
Reading /proc/meminfo
For a live, dynamic picture of memory usage, read /proc/meminfo:
$ cat /proc/meminfo
MemTotal: 258048 kB
MemFree: 198624 kB
Buffers: 1104 kB
Cached: 14320 kB
SwapCached: 0 kB
Active: 41216 kB
Inactive: 2144 kB
Slab: 11648 kB
SReclaimable: 4512 kB
SUnreclaim: 7136 kB
VmallocTotal: 499712 kB
VmallocUsed: 2304 kB
| Field | What It Tells You |
|---|---|
| MemTotal / MemFree | Total usable RAM and how much is currently unallocated |
| Buffers / Cached | Memory used for filesystem caching — reclaimable under pressure |
| Slab / SReclaimable / SUnreclaim | Memory used by the slab allocator; SUnreclaim is memory the kernel cannot give back on demand |
| VmallocUsed | How much of the vmalloc area is currently mapped — a useful early warning if a driver is leaking large buffers |
Hands-On: An Original Module That Reports Its Own Footprint
To make this concrete, here’s a small original module, ep_slabwatch, that reports overall slab memory usage on demand through a procfs entry — a pattern you can reuse whenever you want a quick, driver-level view of memory pressure without parsing full /proc/meminfo output by hand.
// ep_slabwatch.c — reports current slab memory info via /proc/ep_slabwatch
#include <linux/module.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <linux/mm.h>
static int ep_slabwatch_show(struct seq_file *m, void *v)
{
struct sysinfo si;
si_meminfo(&si);
seq_printf(m, "ep_slabwatch: total RAM = %lu kB\n",
si.totalram << (PAGE_SHIFT - 10));
seq_printf(m, "ep_slabwatch: free RAM = %lu kB\n",
si.freeram << (PAGE_SHIFT - 10));
return 0;
}
static int ep_slabwatch_open(struct inode *inode, struct file *file)
{
return single_open(file, ep_slabwatch_show, NULL);
}
static const struct proc_ops ep_slabwatch_fops = {
.proc_open = ep_slabwatch_open,
.proc_read = seq_read,
.proc_lseek = seq_lseek,
.proc_release = single_release,
};
static int __init ep_slabwatch_init(void)
{
proc_create("ep_slabwatch", 0444, NULL, &ep_slabwatch_fops);
pr_info("ep_slabwatch: loaded, read /proc/ep_slabwatch\n");
return 0;
}
static void __exit ep_slabwatch_exit(void)
{
remove_proc_entry("ep_slabwatch", NULL);
}
module_init(ep_slabwatch_init);
module_exit(ep_slabwatch_exit);
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("EmbeddedPathashala: reports live RAM totals via procfs");
$ make -C ~/linux-kernel M=$(pwd) modules
$ sudo insmod ep_slabwatch.ko
$ cat /proc/ep_slabwatch
ep_slabwatch: total RAM = 258048 kB
ep_slabwatch: free RAM = 197312 kB
$ sudo rmmod ep_slabwatch
Common Mistakes and Troubleshooting
- Reading MemFree as “available memory.” A low MemFree is often healthy — Linux deliberately uses spare RAM for filesystem cache and reclaims it instantly under pressure. Watch Cached and reclaimable slab instead of panicking over MemFree alone.
- Ignoring SUnreclaim growth over time. A steadily climbing SUnreclaim value with no corresponding workload increase is one of the earliest visible signs of a kernel-side memory leak, which we’ll diagnose properly later in this chapter.
- Comparing kernel image size across different toolchains without matching configs. The
sizeoutput depends heavily on the exact.configused, compiler version, and optimization flags — only compare builds made with matched settings.
Best Practices
- Snapshot
/proc/meminforight after boot and save it — it becomes your baseline for spotting leaks weeks later. - Run Linux kernel tinification / Linux-tiny style configuration audits periodically on cost-sensitive boards to keep the static kernel image lean.
- Build lightweight procfs reporting (like
ep_slabwatch) into diagnostic-heavy drivers so field devices can self-report memory health without a full debug shell session.
Interview Questions
Q: Why doesn’t a low MemFree value necessarily indicate a memory problem?
Because Linux intentionally uses otherwise-idle RAM for buffer/page cache, which is instantly reclaimable — a healthy system often runs with very little truly free memory.
Q: What’s the practical difference between SReclaimable and SUnreclaim in /proc/meminfo?
SReclaimable slab memory can be freed under memory pressure (e.g., cached inode/dentry objects); SUnreclaim cannot be freed on demand and represents firmer commitment.
Q: Where would you look to see how much vmalloc address space a driver is using?/proc/meminfo‘s VmallocUsed field for a summary, or /proc/vmallocinfo for a per-allocation breakdown with caller information.
Summary and Key Takeaways
- Kernel memory is committed permanently once allocated — never demand-paged, never swapped.
- Major consumers are the kernel image itself, slab allocations, vmalloc buffers, MMIO mappings, and loaded modules.
- The
sizecommand reveals the kernel’s static footprint;/proc/meminforeveals live, dynamic usage. - SUnreclaim and VmallocUsed trends over time are early, practical indicators of kernel-side memory leaks.
Conclusion
Between a board’s boot-time memory map, the static kernel image size, and a live /proc/meminfo reading, you now have the full toolkit for answering “where did my RAM go?” on an embedded Linux target. The next lecture in this free linux kernel development course moves from measuring memory to detecting problems with it — starting with how to spot and diagnose memory leaks using tools ranging from simple procfs snapshots up to mtrace and Valgrind.
FAQ
Is kernel memory ever swapped out like user-space memory?
No. Kernel memory is not demand-paged and is never discarded or swapped — once allocated, it stays resident until explicitly freed.
What’s the fastest way to check total kernel image size?
Run the size command from your cross-toolchain against the uncompressed vmlinux ELF image — it reports text, data, and bss segment sizes immediately.
Why does /proc/meminfo show separate SReclaimable and SUnreclaim slab figures?
They represent different reclaim guarantees: SReclaimable can be freed on demand under memory pressure, while SUnreclaim cannot, which matters a great deal when tuning a RAM-constrained board.
Does a large VmallocTotal mean the board has more RAM?
No — VmallocTotal describes the size of the virtual address range reserved for vmalloc allocations, not physical RAM. On 64-bit systems this range is enormous regardless of installed RAM.
Can loaded kernel modules be a significant source of memory usage?
Yes, especially on boards that load many drivers — each module’s code and data occupies kernel memory for as long as it stays loaded, which is worth auditing on memory-constrained designs.
Where can I learn more for free?
This lecture is part of EmbeddedPathashala’s free embedded systems course, continuing through kernel memory leak detection and out-of-memory handling later in this same chapter.
Continue the Managing Memory Chapter
Next up: detecting kernel and user-space memory leaks, and what happens when an embedded board genuinely runs out of memory.

2 Comments