Skip to main content

Command Palette

Search for a command to run...

The /proc Filesystem: Linux's Window Into the Kernel

Updated
11 min readView as Markdown

Series: Learning Linux Basics | Topic — The proc Filesystem


Introduction

If you've been learning Linux for a while, you've probably typed commands like ps, top, or ulimit without thinking twice about where they get their information. The answer, almost always, is from a special place called the /proc filesystem. Understanding /proc is one of those "aha!" moments that completely changes how you think about Linux — because it reveals that your operating system is far more transparent and observable than most people realize.

In this post, we'll walk through what the /proc filesystem is, why it exists, how it's structured, and how you can use it to inspect and even change the behaviour of your running Linux system — all without rebooting.


What Exactly Is /proc?

The name proc is short for process, because its original purpose was to expose information about running processes. But over the years, it grew into something much bigger: a complete, real-time window into the kernel's internal state.

Here's what makes /proc genuinely unusual: it isn't on your disk. There's no /proc partition. There's no file sitting in storage somewhere. Instead, /proc is what's called a pseudo filesystem — or, put more plainly, a kind of illusion created entirely by the kernel in memory.

When you open or read a file inside /proc, the kernel doesn't fetch bytes from a disk. Instead, it calls a function internally to generate the content right at that moment, and hands the result to you. The file you see is fabricated on demand.

Think of it like this: instead of viewing a photo of a river, you're looking at a live window onto the river itself.


How /proc Gets Mounted

Because /proc is a filesystem (even a virtual one), it needs to be mounted into the Linux directory tree before you can use it. This happens automatically at boot time. The mount command looks like this:

mount -t proc proc /proc

Let's break that down:

Part Meaning
-t proc The type of filesystem to mount is proc
proc The "device" to mount — since there's no real device, we just write proc (some people write none)
/proc The mountpoint — where it appears in your directory tree

Once mounted, /proc looks like an ordinary directory full of files and subdirectories. You can ls it, cat files inside it, and even write to some of them (with the right permissions). But it's all a carefully maintained illusion.


/proc Is Not Like Ordinary Files

One quirk that surprises newcomers: if you run ls -l inside /proc, you'll notice many files report a size of 0 bytes. Yet when you cat those same files, they're full of content. This is not a bug — it's a reminder that these aren't regular files.

ls -l /proc/cpuinfo
# -r--r--r-- 1 root root 0 Mar 29 10:00 /proc/cpuinfo

cat /proc/cpuinfo
# processor       : 0
# vendor_id       : GenuineIntel
# ...

The size is reported as zero because there's nothing stored — the content is generated live each time you access the file. By the time you see the output, it's typically just a few milliseconds old, so it's essentially real-time system information.

Permissions in /proc

Files inside /proc behave like normal files when it comes to permissions:

  • Readable files — most process information can be read by any user (for their own processes) or by root.

  • Writable files — certain files, particularly under /proc/sys, can be written to in order to change kernel behaviour. These are generally writable only by root to prevent non-privileged users from altering system-level settings.


The Structure of /proc: What Lives Where

1. Per-Process Directories

Every process running on your system gets its own numbered subdirectory inside /proc. The directory name is the process's PID (Process ID).

/proc/
├── 1/          ← init/systemd (PID 1)
├── 483/        ← some other process
├── 1234/       ← your process
├── ...

So if a process has PID 1234, you can learn everything about it by looking inside /proc/1234/.

Finding your shell's PID

In a terminal, the special variable $$ holds the PID of your current shell:

echo $$
# 6064

You can then navigate directly to its proc directory:

cd /proc/$$
# Now you're in /proc/6064

Key Files Inside a Process Directory

Inside each per-process directory, there are several important files. Here are the most relevant ones for performance monitoring:

/proc/[PID]/stat — Raw Process Statistics

cat /proc/$$/stat
# 6064 (bash) S 6063 6064 6064 34816 6064 4194304 ...

This file contains a dense, machine-readable stream of numbers — CPU time, memory usage, scheduling state, parent PID, and much more. The values aren't labeled, so you need to cross-reference the man proc documentation to interpret each field. Tools like ps parse this file internally.

/proc/[PID]/statm — Memory Information (Compact)

cat /proc/$$/statm
# 3456 1234 890 123 0 456 0

This is a compact, space-separated line of seven numbers, each representing a memory metric in pages (typically 4 KB each). The fields represent: total program size, resident set size, shared pages, text (code), library, data+stack, and dirty pages.

/proc/[PID]/status — Human-Readable Process Info

cat /proc/$$/status

Sample output:

Name:   bash
State:  S (sleeping)
Pid:    6064
PPid:   6063
VmPeak:    15432 kB    ← Peak virtual memory size
VmSize:    15208 kB    ← Current virtual memory size
VmRSS:      3456 kB    ← Resident Set Size (actual RAM used)
VmPin:         0 kB    ← Pinned (non-swappable) memory
Threads: 1
...

This is the most approachable of the three — it's labeled, readable, and mirrors what ps shows. The Vm lines (Virtual Memory) are especially useful for performance work:

Field Meaning
VmPeak The highest amount of virtual memory the process has ever used
VmSize Current virtual memory footprint
VmRSS Resident Set Size — actual RAM currently consumed
VmPin Memory that's been "pinned" and cannot be swapped out

💡 Why is the process "sleeping"? The shell is in a S (sleeping) state because it's waiting on a child process (in this case, the more pager used to view the status file). This is completely normal.

/proc/[PID]/limits — Resource Limits

cat /proc/$$/limits
Limit                     Soft Limit   Hard Limit   Units
Max cpu time              unlimited    unlimited    seconds
Max file size             unlimited    unlimited    bytes
Max data size             unlimited    unlimited    bytes
Max open files            1024         4096         files
...

This shows the resource limits applied to the process — maximum open file handles, CPU time, stack size, and more. You can also view and set these with the ulimit command in your shell, which reads from and writes to the same underlying kernel data.

/proc/[PID]/numa_maps — NUMA Memory Mapping

cat /proc/$$/numa_maps

This file is more advanced and only truly relevant on large multi-processor servers. NUMA stands for Non-Uniform Memory Access — a hardware architecture where a system has multiple memory banks, each physically closer to certain CPUs.

On such machines, a process accessing memory that's local to its CPU is faster than accessing memory on a remote board. numa_maps shows you where in physical memory each region of a process's address space is located, and which NUMA node it belongs to. This matters for tuning high-performance server applications.

/proc/[PID]/sched — CPU Scheduling Statistics

cat /proc/$$/sched

This file exposes detailed scheduling statistics — how many times the process has been scheduled onto a CPU, how much time it's spent waiting to run, voluntary vs. involuntary context switches, and more. It's a goldmine for diagnosing performance bottlenecks related to CPU contention.


/proc/sys — Kernel Tuning Variables

Beyond per-process information, /proc has a special subdirectory called /proc/sys. This area maps directly to kernel configuration variables — settings that control how the kernel behaves.

/proc/sys/
├── kernel/       ← General kernel settings
├── net/          ← Network stack settings
│   └── ipv4/     ← IPv4-specific network variables
├── vm/           ← Virtual memory settings
├── fs/           ← Filesystem settings
└── ...

Reading a Kernel Variable

cat /proc/sys/net/ipv4/ip_forward
# 0

A value of 0 means IP forwarding is disabled. A value of 1 means it's enabled (important for systems acting as routers).

Writing a Kernel Variable (as root)

echo 1 > /proc/sys/net/ipv4/ip_forward

This immediately enables IP forwarding — no reboot required. This is one of the most powerful aspects of /proc: live kernel tuning.

⚠️ Root required. Writing to /proc/sys files requires root privileges. Ordinary users can read these files, but cannot change them.


The sysctl Command: A Friendlier Interface to /proc/sys

Working directly with /proc/sys paths can be verbose. The sysctl utility provides a cleaner, more ergonomic way to do the same thing.

List All Kernel Variables

sysctl -a

This lists every tunable kernel variable. The output uses dot notation instead of path separators:

/proc/sys path sysctl name
/proc/sys/net/ipv4/ip_forward net.ipv4.ip_forward
/proc/sys/vm/swappiness vm.swappiness
/proc/sys/kernel/hostname kernel.hostname

Read a Specific Variable

sysctl net.ipv4.ip_forward
# net.ipv4.ip_forward = 0

Write a Variable (Temporarily)

sysctl -w net.ipv4.ip_forward=1

This is equivalent to echo 1 > /proc/sys/net/ipv4/ip_forward.


Making Changes Permanent: /etc/sysctl.conf

Here's a crucial catch: changes written to /proc/sys are temporary. The moment you reboot, the kernel resets everything back to its compiled-in defaults. If you need a setting to survive reboots, you must persist it.

The Persistence File

Depending on your Linux distribution, kernel parameters are persisted in one of these locations:

  • /etc/sysctl.conf — traditional, single-file approach

  • /etc/sysctl.d/ — modern, directory-based approach where you drop .conf files

Example: Persist IP Forwarding

# Edit (or create) /etc/sysctl.d/99-custom.conf
echo "net.ipv4.ip_forward = 1" >> /etc/sysctl.d/99-custom.conf

On next boot (or immediately via sysctl --system), this value will be automatically applied.

Applying Immediately Without Reboot

sysctl --system
# or
sysctl -p /etc/sysctl.conf

Common Tools That Use /proc Behind the Scenes

Many familiar Linux commands are really just friendly frontends for /proc data:

Command Where It Gets Data
ps aux /proc/[PID]/stat, /proc/[PID]/status
top / htop /proc/[PID]/stat, /proc/meminfo, /proc/cpuinfo
ulimit /proc/[PID]/limits
free /proc/meminfo
uptime /proc/uptime
hostname /proc/sys/kernel/hostname
lscpu /proc/cpuinfo

Understanding this relationship means you can always go to the source yourself. If ps doesn't show exactly what you need, you can often find the raw data directly in /proc.


Quick Reference: Useful /proc Files for Performance Work

File What It Shows
/proc/cpuinfo CPU model, cores, flags, frequency
/proc/meminfo RAM usage, swap, cached pages
/proc/loadavg 1/5/15-minute load averages
/proc/uptime System uptime and idle time
/proc/net/dev Per-interface network statistics
/proc/diskstats Per-device I/O statistics
/proc/[PID]/status Per-process: state, memory, threads
/proc/[PID]/limits Per-process resource limits
/proc/[PID]/fd/ Open file descriptors for a process
/proc/sys/vm/swappiness How aggressively the kernel uses swap

Summary

The /proc filesystem is one of Linux's most elegant design choices. Rather than requiring special system calls or complicated APIs to inspect the kernel's state, Linux exposes everything through the universal abstraction of the filesystem — files and directories that you can read with the same tools you use for everything else.

Here's what to remember:

  • /proc is a pseudo filesystem — entirely memory-resident, never written to disk.

  • Its contents are generated on demand by kernel functions when you access them.

  • Files may show zero size in ls, but contain real data when you cat them.

  • Each running process has its own directory named after its PID.

  • Inside a process directory, stat, statm, status, limits, and sched are your go-to files for performance analysis.

  • /proc/sys exposes kernel tuning variables that can be read and (by root) changed live.

  • Use sysctl for a friendlier interface to /proc/sys.

  • Persist changes through /etc/sysctl.conf or /etc/sysctl.d/.

The more comfortable you get poking around /proc directly, the deeper your intuition for Linux performance will become. Most of the information that monitoring tools display starts here — so going to the source is always an option.