/proc Internals
/proc is a virtual filesystem — nothing on disk, generated by the kernel on read. Every read returns live kernel data.
/proc/[pid]/maps — Virtual Address Space
cat /proc/1234/maps
55a3c1200000-55a3c1201000 r--p 00000000 08:01 123456 /usr/bin/myapp
55a3c1201000-55a3c1220000 r-xp 00001000 08:01 123456 /usr/bin/myapp
55a3c1220000-55a3c1228000 r--p 00020000 08:01 123456 /usr/bin/myapp
55a3c1228000-55a3c122a000 rw-p 00028000 08:01 123456 /usr/bin/myapp
55a3c3000000-55a3c3021000 rw-p 00000000 00:00 0 [heap]
7f8b12000000-7f8b14000000 rw-p 00000000 00:00 0 [anon]
7fff9a000000-7fff9a021000 rw-p 00000000 00:00 0 [stack]
7fff9a1fe000-7fff9a202000 r--p 00000000 00:00 0 [vvar]
7fff9a202000-7fff9a204000 r-xp 00000000 00:00 0 [vdso]
Column breakdown:
| Column | Meaning |
|---|---|
55a3c1200000-55a3c1201000 |
Virtual address range (start-end) |
r--p |
Permissions: read/write/execute + private(p) or shared(s) |
00000000 |
File offset (where in the file this mapping starts) |
08:01 |
Device (major:minor) |
123456 |
Inode number |
/usr/bin/myapp |
Backing file (empty = anonymous) |
Permission flags:
rread,wwrite,xexecute,-not setpprivate (copy-on-write),sshared
Named regions:
[heap]—mallocarena[stack]— main thread stack[anon]— anonymous mappings (goroutine stacks, JVM heap, mmap'd allocations)[vdso]— virtual dynamic shared object (kernel exposes clock_gettime here to avoid syscall overhead)
# Count memory regions
wc -l /proc/1234/maps
# Find all shared libraries loaded
grep "\.so" /proc/1234/maps | awk '{print $6}' | sort -u
# Find heap size
grep "\[heap\]" /proc/1234/maps
# Find all anonymous mappings (goroutine stacks, JVM heap)
grep "00:00 0" /proc/1234/maps | grep -v "\["
/proc/[pid]/smaps — Per-Mapping Memory Stats
smaps is maps with detailed RSS/PSS/swap breakdown per region.
cat /proc/1234/smaps
55a3c1201000-55a3c1220000 r-xp 00001000 08:01 123456 /usr/bin/myapp
Size: 124 kB ← virtual size of this mapping
KernelPageSize: 4 kB
MMUPageSize: 4 kB
Rss: 96 kB ← pages in physical RAM
Pss: 48 kB ← proportional share (RSS / # processes sharing)
Shared_Clean: 96 kB ← shared + unmodified (can be discarded)
Shared_Dirty: 0 kB ← shared + modified (must be kept)
Private_Clean: 0 kB ← private + unmodified
Private_Dirty: 0 kB ← private + modified (your actual footprint)
Referenced: 96 kB ← recently accessed
Anonymous: 0 kB ← not file-backed
Swap: 0 kB ← pages swapped out
Key metrics:
| Field | Use |
|---|---|
Rss |
Physical RAM used by this mapping |
Pss |
Fairer than RSS — shared pages divided by sharing count |
Private_Dirty |
Your process's actual unique memory footprint |
Swap |
Bytes of this mapping currently on swap |
# Summarized rollup (fastest)
cat /proc/1234/smaps_rollup
# Rss: 45632 kB
# Pss: 32768 kB
# Private_Dirty: 28672 kB
# Swap: 0 kB
# Total swap used by process
awk '/Swap:/ {sum += $2} END {print sum " kB"}' /proc/1234/smaps
# Largest anonymous mappings (heap, goroutine stacks, JIT)
awk '/^[0-9a-f]/{map=$0} /Anonymous:/{print $2, map}' /proc/1234/smaps \
| sort -rn | head -10
/proc/[pid]/status — Process Summary
cat /proc/1234/status
Name: myapp
State: S (sleeping)
Pid: 1234
PPid: 1000
Threads: 8
VmPeak: 512000 kB ← peak virtual memory ever used
VmSize: 480000 kB ← current virtual memory
VmRSS: 45632 kB ← current RSS (physical RAM)
VmData: 32768 kB ← heap + BSS (data segment)
VmStk: 132 kB ← main thread stack
VmExe: 124 kB ← text segment (code)
VmLib: 8192 kB ← shared libraries
RssAnon: 28672 kB ← anonymous RSS (heap, stacks)
RssFile: 16960 kB ← file-backed RSS (code, mmapped files)
SigBlk: 0000000000000000 ← blocked signals (bitmask)
SigIgn: 0000000000001000 ← ignored signals
SigCgt: 0000000180000000 ← caught signals (has handler)
voluntary_ctxt_switches: 1234 ← gave up CPU voluntarily
nonvoluntary_ctxt_switches: 56 ← preempted by kernel
What to look for:
| Field | If high/growing | Likely cause |
|---|---|---|
VmRSS growing |
Memory leak | Use smaps to find growing region |
nonvoluntary_ctxt_switches high |
CPU contention | Too many threads competing |
Threads high |
Thread leak | Worker pool not bounded |
VmSize >> VmRSS |
Normal (Go, JVM over-reserve) | Virtual ≠ physical |
/proc/[pid]/fd — Open File Descriptors
# Count open FDs
ls /proc/1234/fd | wc -l
# See what each FD points to
ls -la /proc/1234/fd
# lrwx 0 -> /dev/pts/0 (terminal)
# lrwx 1 -> pipe:[123456] (stdout pipe)
# lrwx 5 -> socket:[789012] (TCP connection)
# lrwx 7 -> /var/log/app.log (open file)
# lrwx 9 -> anon_inode:epoll (epoll FD — Go netpoller)
# Find all open sockets
ls -la /proc/1234/fd | grep socket
# FD limit vs current
cat /proc/1234/limits | grep "open files"
/proc/[pid]/net/tcp — TCP Connections
cat /proc/1234/net/tcp
# sl local_address rem_address st ...
# 0: 00000000:1F90 00000000:0000 0A ... ← LISTEN on :8080
# 1: 0F02000A:1F90 0102000A:C3E0 01 ... ← ESTABLISHED
# Decode hex address (little-endian)
# 0F02000A = 10.0.2.15, 1F90 = 8080
# State 0A = LISTEN, 01 = ESTABLISHED, 06 = TIME_WAIT
Other Useful /proc Files
# System-wide
cat /proc/loadavg # 1.23 0.45 0.32 2/456 12345
# load1 load5 load15 running/total lastpid
cat /proc/sys/kernel/pid_max # max PID (default 32768)
cat /proc/sys/fs/file-nr # open FDs / free / max
cat /proc/sys/net/ipv4/ip_local_port_range # ephemeral port range
# Per-process
cat /proc/1234/cmdline | tr '\0' ' ' # full command line
cat /proc/1234/environ | tr '\0' '<br>' # environment variables
cat /proc/1234/wchan # kernel function process is sleeping in
cat /proc/1234/schedstat # CPU time, wait time, switches