DevOpsIndex

/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:

  • r read, w write, x execute, - not set
  • p private (copy-on-write), s shared

Named regions:

  • [heap]malloc arena
  • [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