/proc 분석기
/proc/meminfo, /proc/buddyinfo, /proc/interrupts 같은 파일 내용을 붙여넣으면 메모리 압박·단편화·IRQ 편중·락 경합을 자동으로 진단합니다.
최근 분석 0
분석 메모 (리포트·공유 URL 에 자동 포함 — 관찰·가설·조치·영향)
📚 포맷 · 계산식 · 판정 임계치 설명
이 도구는 단순한 문자열 매칭이 아니라, 각 /proc/ 파일의 의미를 알고 임계치 기반 휴리스틱으로 판정합니다. 아래는 각 파서가 어떤 필드를 읽고 어떤 기준으로 심각도를 매기는지에 대한 전체 설명입니다. 임계치는 실무 경험에 기반한 경험치이므로 환경에 따라 조정이 필요할 수 있습니다.
공통 심각도 체계
모든 판정은 다음 4단계로 분류합니다.
- 심각 (danger) — 즉시 조치가 필요한 수준. 장애가 진행 중이거나 임박했다고 판단되는 상태.
- 경고 (warning) — 추세를 모니터링해야 하는 수준. 방치 시 장애로 이어질 수 있음.
- 정보 (info) — 임계치에 근접했거나 주목할 만한 수치. 즉각적 문제는 아님.
- 정상 (ok) — 모든 임계치 아래.
/proc/meminfo
포맷: Key: 값 kB 형태의 단순 key-value. 파서는 각 줄을 정규식 ^([A-Za-z_()0-9]+):\s+(\d+)로 읽어 해시(Hash)에 저장합니다.
주요 계산식:
가용 메모리 비율 = MemAvailable / MemTotal × 100 Dirty 비율 = (Dirty + Writeback) / MemTotal × 100 Slab 비율 = Slab / MemTotal × 100 SUnreclaim 비중 = SUnreclaim / Slab × 100 Swap 사용률 = (SwapTotal − SwapFree) / SwapTotal × 100 Commit 비율 = Committed_AS / CommitLimit × 100판정 임계치:
| 항목 | 심각 | 경고 | 정보 |
|---|---|---|---|
| MemAvailable 비율 | < 5% | < 10% | < 20% |
| Dirty+Writeback 비율 | > 20% | > 10% | — |
| Slab 비율 | > 25% | > 15% | — |
| SUnreclaim/Slab | — | > 60% 그리고 > 500 MiB | — |
| Swap 사용률 | > 80% | > 50% | — |
| Committed_AS/CommitLimit | > 95% | — | — |
| HugePages_Free | — | — | = 0 (전량 사용) |
MemAvailable 이 누락된 구식 커널에서는 MemFree + Cached + Buffers 를 폴백으로 사용합니다. 이는 완벽하지 않지만 v3.14 이전 환경에서 최선의 근사치입니다.
/proc/buddyinfo
포맷: Node N, zone ZONE order0 order1 ... order10. 각 order 는 해당 크기의 여유 블록 개수입니다. order o 는 2o 페이지(Page) (= 2o × 4KiB) 를 의미합니다.
주요 계산식:
총 페이지 = Σ (count[o] × 2^o) high-order 페이지 = Σ (count[o] × 2^o) [o ≥ 3] 단편화 점수 = (1 − high-order 페이지 / 총 페이지) × 100 최대 가용 order = max{ o | count[o] > 0 }판정 임계치 (Normal/Movable/HighMem 존에서 총 256 페이지 초과인 경우만):
- 심각: 최대 가용 order < 3 — 32 KiB 이상 연속 할당이 즉시 실패. compaction·direct reclaim 루프 진입이 예상됩니다.
- 경고: 최대 가용 order < 5 — 128 KiB 이상 할당 불가. huge-page·jumbo frame·대형 skb 가 실패할 수 있습니다.
DMA 존은 원래 작아서 고차 블록이 드물므로 판정에서 제외합니다. 단편화 점수는 표에 색상 bar 로 시각화됩니다.
/proc/slabinfo
포맷: 첫 줄 slabinfo - version: 2.1, 이후 각 캐시마다 name active_objs num_objs objsize objperslab pagesperslab : tunables ... : slabdata .... 파서는 앞 4개 필드만 사용합니다.
주요 계산식:
캐시 사용량 (bytes) = active_objs × objsize 전체 합계 = Σ (캐시별 사용량) 상위 15개만 표시하고 사용량 내림차순으로 정렬의심 캐시 자동 태깅: 다음 캐시 이름이 일정 크기 이상이면 특정 증상으로 태깅합니다.
dentry,inode_cache,ext4_inode_cache,xfs_inode— VFS 캐시 누수 (대량 파일 스캔, negative dentry 폭주)kmalloc-1k,kmalloc-2k,buffer_head— 일반 슬랩 비대skbuff_head_cache,TCP,sock_inode_cache,filp— 네트워크/fd 누수task_struct,anon_vma— 프로세스(Process)/VMA 누수
임계치: 50 MiB 초과 시 경고, 500 MiB 초과 시 심각.
/proc/interrupts 및 /proc/softirqs
포맷: 첫 줄이 CPU0 CPU1 CPU2 ... 헤더, 이후 각 IRQ 또는 softirq 마다 NAME: c0 c1 c2 ... 추가 메타데이터. 파서는 공통 루틴 parseCpuTable() 로 처리하며, 두 파일은 키워드로 구분합니다. HI/TIMER/NET_TX/NET_RX/... 같은 softirq 이름이 보이면 softirqs 로 판정합니다.
편중 계산식:
sum = Σ counts[i] max = max(counts) maxCpu = argmax(counts) avg = sum / CPU 수 skew 배수 = max / avg (분포가 균일하면 1.0)IRQ 편중 판정 (일반 IRQ):
- CPU 수 ≥ 4 그리고 총합 > 10,000 그리고 skew > CPU 수 × 0.6 → 경고
- 예: 4 CPU 시스템에서 skew > 2.4 이면 편중 판정. irqbalance 가 꺼져 있거나 affinity 가 고정된 상태일 가능성이 높습니다.
softirq 편중 판정:
NET_RX/NET_TX: CPU ≥ 4, 총합 > 100,000, skew > CPU 수 × 0.5 → 경고 (RSS/RPS/XPS 설정 문제 의심)TIMER: CPU ≥ 4, 총합 > 1,000,000, skew > CPU 수 × 0.5 → 정보 (hrtimer 편향)TASKLET: 총합 > 1,000,000, skew > CPU 수 × 0.7 → 정보 (tasklet 은 전통적으로 발생 CPU 에 바인딩됨)
NMI/MCE 이상치: NMI 총합 > 1,000 회 또는 MCE 총합 > 0 이면 즉시 심각. MCE 는 하드웨어 오류 (DRAM/CPU/PCIe) 의 직접적 증거이므로 mcelog, edac-util 추적이 필수입니다.
/proc/vmstat
포맷: 카운터_이름 값 형태의 단순 key-value. 파서는 ^(\S+)\s+(-?\d+) 로 읽습니다.
주요 파생 지표:
direct reclaim 누적 = Σ allocstall_* direct scan 비율 = pgscan_direct_* / (pgscan_direct_* + pgscan_kswapd_*) × 100판정 임계치:
| 카운터 | 심각 | 경고 |
|---|---|---|
allocstall_* 합 | > 10,000 | > 0 |
compact_fail | > 10,000 | > 1,000 |
pgmajfault | > 1,000,000 | > 100,000 |
oom_kill | > 0 | — |
pswpin + pswpout | — | > 1,000,000 |
| direct scan 비율 | — | > 30% |
vmstat 는 부팅 이후 누적 카운터이므로, 절대값보다 추세(두 시점 간 차이) 관찰이 본질적으로 더 유용합니다. 이 도구는 절대값만으로 판정하므로, 장기 가동된 시스템에서는 일부 경고가 과대 평가될 수 있습니다.
/proc/pressure/{cpu,memory,io} (PSI)
포맷: 각 파일이 최대 2줄.
some avg10=X avg60=X avg300=X total=N full avg10=X avg60=X avg300=X total=N- some — 최소 하나의 태스크(Task)가 리소스를 기다린 시간 비율 (%)
- full — 모든 실행 가능 태스크가 동시에 기다린 시간 비율 (%).
cpu는 full 이 없음 - avg10/60/300 — 최근 10초·60초·300초 지수 이동 평균
- total — 부팅 이후 누적 stall 시간 (마이크로초)
판정: max(avg10, avg60, avg300) 기준으로 다음 구간에 따라 분류합니다.
- > 50 — 심각 (사실상 정체 상태)
- > 20 — 경고 (사용자 체감 지연(Latency))
- > 5 — 정보 (경미한 압박)
- 그 외 — 정상
PSI 는 Linux 4.20 부터 제공되며, some 보다 full 이 훨씬 심각한 신호입니다. full 이 10 을 넘으면 시스템 전체가 해당 리소스 때문에 멈춰 있다는 뜻입니다.
/proc/lock_stat
포맷: CONFIG_LOCK_STAT=y 로 빌드된 커널에서만 제공. 헤더 다음에 각 락 클래스마다 name: con-bounces contentions waittime-min waittime-max waittime-total holdtime-min holdtime-max holdtime-total 형태의 줄이 나옵니다.
파싱: 파서는 관대하게 접근하여 ^(\S+):\s+(\d+)\s+(\d+)\s+(\S+)\s+(\S+)\s+(\S+) 패턴에 매칭되는 줄만 추출합니다 (bounces·contentions·wait-max·wait-total).
판정 임계치: 경합 횟수(contentions) 기준.
- > 100,000 → 심각 (핫 락 후보 — 락 분할·RCU 전환·fine-grained 락 검토)
- > 10,000 → 경고
주의: lock_stat 은 런타임 sysctl 토글이 없습니다. 빌드 시점에 CONFIG_LOCK_STAT 가 꺼져 있다면 파일 자체가 없거나 빈 상태입니다. echo 0 > /proc/lock_stat 로 카운터만 리셋할 수 있습니다.
/proc/stat
포맷: 첫 줄은 전체 CPU 합산 cpu, 이후 CPU 별 cpu0 cpu1 .... 각 줄은 10개의 jiffy 카운터 user nice system idle iowait irq softirq steal guest guest_nice. 이어서 intr, ctxt, btime, processes, procs_running, procs_blocked, softirq 줄이 나옵니다.
주요 계산식 (모두 부팅 이후 누적):
total = user + nice + system + idle + iowait + irq + softirq + steal user% = (user + nice) / total × 100 system% = system / total × 100 iowait% = iowait / total × 100 steal% = steal / total × 100 irq 합계% = (irq + softirq) / total × 100 CPU별 busy% = (1 − (idle + iowait) / total) × 100판정 임계치:
| 지표 | 심각 | 경고 |
|---|---|---|
| iowait 누적 비율 | > 40% | > 20% |
| steal 비율 | > 15% | > 5% |
| irq+softirq 비율 | — | > 30% |
| system 비율 | — | > 50% |
| procs_blocked | > 20 | > 5 |
| procs_running | — | > CPU 수 × 4 |
| CPU 간 busy 격차 | — | > 50%p (그리고 최대 CPU 가 > 60%) |
btime 은 Unix 에폭 초 단위 부팅 시각입니다. 도구는 이를 UTC 사람 가독 형식으로 변환하고, 현재 시간과의 차이로 추정 uptime 을 계산합니다. 브라우저 시각이 기준이므로 서버가 UTC 가 아닌 경우 약간 어긋날 수 있습니다.
누적 카운터 한계: 이 파일의 대부분은 부팅 이후 누적값이므로, 짧은 스파이크는 희석되어 드러나지 않을 수 있습니다. 실시간(Real-time) 스냅샷 성격은 procs_running, procs_blocked 뿐입니다.
/proc/loadavg
포맷: 한 줄. load1 load5 load15 running/total last_pid.
load1/5/15— 지수 이동 평균 기반 run queue 크기 + uninterruptible 태스크 수의 1/5/15분 평균running/total— 현재 실행 가능 태스크 / 전체 태스크last_pid— 마지막으로 할당된 PID
판정 임계치: 이 도구는 CPU 개수를 알 수 없으므로 절대값 기준으로 분류합니다.
max(load1,5,15) > 50→ 심각max(load1,5,15) > 20→ 경고load1 > load15 × 1.5이고load1 > 5→ 정보 (단기 급상승)
실제 판정 기준은 load / CPU 수 입니다. 이 비율이 1 이면 CPU 가 완전히 가득 찬 상태, 2 이상이면 대기가 발생하는 과부하로 해석합니다. 정확한 판정을 위해서는 /proc/cpuinfo 또는 /proc/stat 의 CPU 수와 함께 해석해야 합니다.
/proc/uptime
포맷: 한 줄. uptime_sec idle_sec. idle 은 모든 CPU 합산 이므로 실제 경과 시간보다 훨씬 클 수 있습니다. idle / uptime ≈ CPU 수 근사(100% idle 가정 시 상한선) 로 대략의 CPU 수를 유추할 수 있습니다.
판정: uptime 600초 미만이면 "최근 재부팅·장애 복구 직후" 로 표시합니다. 누적 카운터 해석에 주의하라는 의미입니다.
/proc/diskstats
포맷: 각 줄이 major minor name reads reads-merged sectors-read ms-reading writes writes-merged sectors-written ms-writing ios-in-progress total-ms-io weighted-ms-io 의 14개 이상 필드. 최신 커널은 discard/flush 필드가 추가되지만 이 도구는 앞 14개만 사용합니다.
주요 계산식:
read MB = sectors_read × 512 / 1024 / 1024 write MB = sectors_written × 512 / 1024 / 1024 평균 대기 = (ms_reading + ms_writing) / (reads + writes)판정 임계치 — 단일 스냅샷으로 의미가 있는 것은 in-flight I/O 뿐입니다.
in-flight > 32→ 심각in-flight > 8→ 경고in-flight > 0→ 정보
나머지 누적 카운터는 표로만 보여줍니다. 실시간 포화도 판정은 iostat -x 1 같은 구간 샘플링 도구가 본질적으로 더 적합합니다.
/proc/net/dev
포맷: 상단 2줄 헤더 + 각 인터페이스당 1줄. iface: rx_bytes rx_pkts rx_errs rx_drop rx_fifo rx_frame rx_compressed rx_multicast tx_bytes tx_pkts tx_errs tx_drop tx_fifo tx_colls tx_carrier tx_compressed.
판정 임계치 (lo 는 제외):
rx_drop > 100,000→ 심각,> 1,000→ 경고 — 수신 큐 포화. softirq NET_RX 가 따라가지 못하거나 RPS/RFS 미설정rx_errs > 100→ 경고 — 링크 계층 오류 (CRC, 듀플렉스 불일치, 물리 계층 문제)tx_errs > 100또는tx_carrier > 10→ 경고 — 링크 플랩 (carrier loss)- 에러율 = (전체 에러 합) / (전체 패킷(Packet) + 에러 합) × 100, > 5% 심각, > 1% 경고
누적 카운터이므로 장기간 가동된 시스템에서는 과거 일회성 에러가 경고로 과대 평가될 수 있습니다.
/proc/net/sockstat
포맷: 프로토콜별 줄. proto: key1 val1 key2 val2 ... 형태의 공백 분리 key-value.
주요 카운터 의미:
TCP inuse— 현재 활성 TCP 소켓(Socket) 수TCP tw— TIME_WAIT 상태 소켓 수TCP orphan— 애플리케이션이 close 했지만 커널이 정리 중인 소켓 수TCP mem— TCP 가 점유한 메모리 페이지 수 (페이지당 보통 4 KiB)FRAG memory— IP 재조립 버퍼(Buffer) 메모리 (bytes)
판정 임계치:
TCP tw > 100,000→ 경고,> 30,000→ 정보 — 단기 연결 폭주 워크로드TCP orphan > 100→ 경고 —tcp_max_orphans근접 시 강제 종료 발생TCP mem > 100,000 pages(≈ 400 MiB) → 정보FRAG memory > 1 MiB→ 경고 — 프래그먼트 공격 또는 MTU 문제 의심
/proc/swaps
포맷: 첫 줄 Filename Type Size Used Priority 헤더, 이후 각 swap 장치당 1줄.
판정 임계치:
- 개별 장치 사용률
> 80%→ 심각 - 개별 장치 사용률
> 50%→ 경고 - swap 장치가 전무한 경우 → 정보 (메모리 압박 시 OOM-Killer 즉시 동작)
/proc/cpuinfo
포맷: 빈 줄로 구분된 논리 CPU 별 블록. 각 블록은 key : value 형태. processor 번호, model name, physical id, core id, flags, bugs 등 필드를 사용합니다.
주요 계산:
- 논리 CPU 수 = 블록 개수
- 물리 코어 수 = 고유한
(physical id, core id)쌍 개수 - SMT 배수 = 논리 / 물리 — 2 이상이면 Hyper-Threading 활성
판정:
bugs:필드의 취약점 목록이 5개 이상 → 경고. 그 미만은 정보. 커널 mitigation 적용 여부는/sys/devices/system/cpu/vulnerabilities/*로 따로 확인해야 합니다.- 보안 플래그 (
smep,smap,pcid,nx,umip) 중 3개 이상 누락 → 정보 hypervisor플래그 존재 → 가상화(Virtualization) 환경 감지 (정보)- SMT 활성 → 정보 (
nosmt권장 여부는 워크로드 별 판단)
/proc/cmdline
포맷: 한 줄, 공백 분리 key=value 또는 플래그 토큰. BOOT_IMAGE, root, console, initrd 는 정보로 표시하고, 보안·성능 관련 파라미터는 위험도에 따라 분류합니다.
위험 플래그 판정:
- 심각:
mitigations=off,iommu=off,selinux=0,apparmor=0,nomodule - 경고:
nopti(KPTI 비활성),nokaslr - 정보:
mitigations=auto,nosmt,nosmt,lockdown,audit,panic,quiet - 정상:
crashkernel=*설정 (kdump 준비 완료 신호)
mitigations=off 는 Meltdown/Spectre/L1TF/MDS/RetBleed 등 주요 투기 실행 취약점 완화를 모두 끕니다. 전용 신뢰 네트워크 밖에서는 사실상 금지해야 합니다.
/proc/version
포맷: 한 줄, Linux version X.Y.Z-build (user@host) (compiler info) #n SMP ... date. 커널 버전, 빌드 주체, 컴파일러, 빌드 번호·날짜를 분해해 표시합니다.
LTS 힌트: 4.19, 5.4, 5.10, 5.15, 6.1, 6.6, 6.12 등 알려진 LTS 버전이면 정상(ok) 태그가 붙습니다. 판정이라기보다 참고용입니다.
/proc/modules
포맷: 각 줄이 name size instances deps state addr [taints]. state 는 Live/Loading/Unloading, taint 는 선택적으로 괄호 안에 글자 조합.
주요 판정:
- Taint 마크가 붙은 모듈이 있으면 경고. 글자 의미:
P=proprietary,O=out-of-tree,E=unsigned,F=force-loaded,R=force-unloaded - Live 가 아닌 상태 모듈이 있으면 정보 (덤프(Dump) 시점에 전이 중이면 의심)
- 상위 12개 모듈을 메모리 크기 기준으로 정렬해 표로 표시
/proc/net/snmp
포맷: 프로토콜별로 짝수 줄 (헤더 1줄, 데이터 1줄). Ip:, Icmp:, Tcp:, Udp:, UdpLite: 등이 있습니다. 파서는 헤더 줄의 필드 이름과 데이터 줄의 숫자를 매핑(Mapping)해 key-value 레코드로 만듭니다.
주요 계산식:
TCP 재전송률 = RetransSegs / OutSegs × 100판정 임계치:
| 지표 | 심각 | 경고 |
|---|---|---|
| TCP 재전송률 (OutSegs > 1000) | > 5% | > 2% |
| TCP AttemptFails | — | > 1,000 |
| TCP EstabResets | — | > 10,000 (정보) |
| UDP InErrors / RcvbufErrors | — | > 0 |
누적 카운터이므로 장기 가동 시스템에서는 과거 스파이크가 남아 있을 수 있습니다. 재전송률 2% 는 일시적 네트워크 이벤트의 평균까지 포함한 보수적 임계치입니다.
/proc/net/softnet_stat
포맷: CPU 당 한 줄, 공백 분리 16진수 워드 11개. 주요 필드 순서: processed dropped time_squeeze (이후 4개는 폐기, 5번째 cpu_collision, 6번째 received_rps, 7번째 flow_limit_count).
필드 의미:
- processed — 이 CPU 의 softirq 가 처리한 패킷 수 (누적)
- dropped — backlog 큐 가득 차서 드롭된 패킷 수.
/proc/net/dev의 rx_drop 과 직결 - time_squeeze — NET_RX softirq 가 한 턴에
net.core.netdev_budget(기본 300) 을 소진해 ksoftirqd 로 넘긴 횟수 - flow_limit_count — Flow Limit 이 한 플로우가 backlog 를 독점하지 못하도록 드롭한 횟수
판정 임계치:
dropped 합계 > 100,000→ 심각,> 0→ 경고.net.core.netdev_max_backlog상향 검토time_squeeze 합계 > 100,000→ 경고,> 10,000→ 정보.net.core.netdev_budget·netdev_budget_usecs상향 검토
/proc/sys/fs/file-nr
포맷: 한 줄 3개 정수 — allocated unused max. max 는 fs.file-max sysctl 의 현재값입니다.
계산식: 사용률 = allocated / max × 100
판정 임계치:
> 90%→ 심각 — 전역 fd 고갈 임박. 초과 시 모든open(2)가EMFILE/ENFILE로 실패> 70%→ 경고 — 누수 의심 또는fs.file-max상향 검토
개별 프로세스의 fd 한계 (ulimit -n, /proc/[pid]/limits) 와는 별개의 시스템 전역 한계입니다.
/proc/sys/fs/inode-nr
포맷: 한 줄 2개 정수 — allocated unused. file-nr 와 달리 상한(inode-max) 은 없습니다 (커널이 동적으로 관리).
계산: in-use = allocated − unused, 사용률 = in-use / allocated × 100.
판정 임계치:
allocated > 10,000,000→ 경고 — 대량 파일 스캔, inode 누수, 또는 negative dentry 폭주 의심./proc/slabinfo의inode_cache/dentry캐시와 교차 확인.- 사용률
> 95%이고 allocated> 100,000→ 정보 — unused 여유가 거의 없어 reclaim 시 회수 대상 부족.
/proc/net/netstat
포맷: net/snmp 와 동일한 짝수 줄 구조 — 프로토콜별 헤더(TcpExt:, IpExt:) 다음에 숫자 데이터 줄. 파서는 parseSnmp() 를 재사용합니다.
핵심 카운터:
ListenOverflows— accept 큐 가득 찼을 때 새 연결이 버려진 횟수. 서버 장애 1순위 지표ListenDrops— listen 소켓이 SYN 을 drop 한 총 횟수 (SYN 큐 혹은 accept 큐 포화 시)TCPBacklogDrop— established 소켓의 backlog 큐 드롭 (애플리케이션이 읽지 않음)SyncookiesSent/Recv/Failed— SYN flood 완화 동작TCPFastRetrans / TCPSlowStartRetrans / TCPForwardRetrans— 재전송 세분화TCPLostRetransmit— 재전송한 세그먼트가 다시 손실TCPSpuriousRTOs— 잘못된 타임아웃으로 불필요한 재전송PAWSEstab— PAWS 로 드롭된 세그먼트 (NAT 뒤 TIME_WAIT 재사용 전형)
주요 계산식:
재전송 손실률 = TCPLostRetransmit / (TCPFastRetrans + TCPSlowStartRetrans + TCPForwardRetrans) × 100판정 임계치:
| 지표 | 심각 | 경고 |
|---|---|---|
ListenOverflows | > 0 | — |
ListenDrops | > 1,000 | > 0 |
TCPBacklogDrop | > 100,000 | > 1,000 |
| 재전송 손실률 | — | > 10% |
SyncookiesFailed | — | > 0 |
net/snmp 는 프로토콜 레벨 요약, net/netstat 는 확장 카운터 (커널 내부 동작 세부) 라는 차이가 있습니다. 서버 장애 진단에서는 보통 net/netstat 가 훨씬 더 구체적인 단서를 제공합니다.
/proc/zoneinfo
포맷: Node N, zone ZONE 헤더 이후 들여쓰기된 키 값 줄들. 주요 필드: pages free, min, low, high, present, nr_free_pages, nr_zone_inactive_anon 등. 모두 4 KiB 페이지 단위.
워터마크 의미:
min— 이 아래로 떨어지면 할당 실패 또는 OOM-Killer 발동.vm.min_free_kbytes의 존별 배분low— 이 아래로 떨어지면 kswapd 가 깨어나 reclaim 시작high— reclaim 이 이 수위 위로 올라오면 멈춤
판정 임계치 (Normal/Movable/HighMem 존):
free < min→ 심각 — 할당 실패·OOM 임박free < low→ 경고 — kswapd 활동 중free < high→ 정보 — high 미만으로 내려간 상태
NUMA 불균형: 노드별 free 합계를 비교하여 가장 작은 노드가 가장 큰 노드의 20% 미만이면 경고. numactl 바인딩이나 vm.zone_reclaim_mode 점검을 권장합니다.
meminfo 가 시스템 전체 합계라면, zoneinfo 는 같은 데이터를 zone·NUMA 노드 단위로 쪼개 보여줍니다. 시스템 총량은 여유로운데 특정 존만 고갈되어 압박을 일으키는 경우 zoneinfo 에서만 원인이 드러납니다.
/proc/sys/kernel/tainted
포맷: 한 줄, 비트마스크 정수. 값이 0 이면 깨끗, 그 외에는 각 비트를 아래 글자로 해석합니다.
비트 → 글자 매핑:
| 비트 | 글자 | 의미 |
|---|---|---|
| 0 | P | proprietary module 로드 (GPL 비호환) |
| 1 | F | force-loaded 모듈 (의존성 무시) |
| 2 | S | SMP 미지원 CPU 에서 SMP 커널 |
| 3 | R | force-unloaded 모듈 |
| 4 | M | Machine Check Exception 발생 |
| 5 | B | Bad page 감지 |
| 6 | U | 사용자가 sysfs 로 taint 직접 요청 |
| 7 | D | 커널이 die (oops) 한 적 있음 |
| 8 | A | ACPI 테이블 덮어쓰기 |
| 9 | W | 커널 WARNING 발생 |
| 10 | C | staging 드라이버 로드 |
| 11 | I | firmware 버그 우회 동작 |
| 12 | O | out-of-tree 모듈 로드 |
| 13 | E | 서명되지 않은 모듈 로드 |
| 14 | L | soft lockup 발생 |
| 15 | K | 커널 라이브 패치(Livepatch) 적용 |
| 16 | X | 보조 taint (배포판 정의) |
| 17 | T | 테스트 서명 커널 |
| 18 | N | in-kernel test 활성 |
심각도 분류:
- 심각:
M(MCE),D(oops),L(soft lockup),B(bad page) — 커널이 실제 장애를 경험한 증거 - 경고:
W(WARN_ON),P/O/E/F/R(모듈 관련) - 정보: 기타
커널 문제를 커뮤니티에 보고할 때 tainted 상태는 필수 정보이며, 0 이 아니면 원인 추적의 출발점으로 삼습니다. /proc/modules 와 교차 분석하면 어떤 모듈이 taint 를 유발했는지 좁힐 수 있습니다.
섹션 분리 로직
여러 /proc/ 파일을 한 번에 붙여넣는 경우 다음 패턴 중 하나로 헤더를 표시하면 됩니다.
파서는 정규식 ^[=#\-\s]*\/proc\/([a-zA-Z0-9_\/]+)[=#\-\s]*$ 로 헤더를 찾습니다. 헤더가 하나도 없으면 전체 입력을 단일 섹션으로 간주하고 자동 형식 감지를 시도합니다.
자동 형식 감지 시그니처:
| 형식 | 감지 패턴 |
|---|---|
meminfo | ^MemTotal:\s+\d+\s*kB 또는 ^Active(anon): |
buddyinfo | ^Node \d+, zone \S+ 및 숫자 열 8개 이상 |
slabinfo | slabinfo - version: 또는 # name <active_objs> |
interrupts vs softirqs | 둘 다 CPU0 CPU1 ... 헤더 — softirq 이름 (HI/TIMER/NET_RX/...) 존재 여부로 구분 |
vmstat | ^nr_free_pages 또는 ^pgpgin |
pressure | ^some avg10= |
lock_stat | lock_stat version 또는 class name con-bounces |
stat | ^cpu \d+ \d+ \d+ 및 ^ctxt \d+ |
loadavg | 한 줄 float float float int/int int |
uptime | 1-2줄, 첫 줄 float float |
swaps | ^Filename Type Size Used Priority |
diskstats | 첫 열이 major 번호(정수)인 14열 이상의 숫자 행 |
net/dev | ^Inter-| Receive 또는 ^ face |bytes packets |
net/sockstat | ^sockets: used \d+ |
cpuinfo | ^processor\s*:\s*\d+ 또는 ^model name\s*: |
version | ^Linux version 으로 시작 |
cmdline | 한 줄에 BOOT_IMAGE= 또는 root= 포함 (헤더 지정 권장) |
modules | name size instances deps (Live|Loading|Unloading) 패턴 |
net/snmp | ^Ip:\s+\S 및 ^Tcp:\s+\S |
net/softnet_stat | 각 줄이 16진수 워드 5개 이상 |
sys/fs/file-nr | 단일 줄, 3개 정수 (헤더 지정 권장) |
net/netstat | ^TcpExt:\s+\S 또는 ^IpExt:\s+\S |
zoneinfo | ^Node \d+, zone \S+$ 및 본문에 pages free |
sys/kernel/tainted | 단일 정수 (헤더 필수) |
sys/fs/inode-nr | 단일 줄, 2개 정수 (헤더 필수) |
⚠ 가상 파일 직접 열기 제약
브라우저에서 /proc/ 파일을 "파일 열기" 로 직접 선택할 수는 없습니다. procfs 는 가상 파일시스템(VFS)이라 stat() 이 파일 크기를 0 으로 보고하고, 브라우저의 File API 는 이 값을 기준으로 Blob 을 구성하므로 실제 내용을 읽지 못하고 빈 문자열을 돌려줍니다. 이건 Chromium·Firefox 모두 동일한 보안 샌드박스(Sandbox) 동작입니다.
대안:
- 터미널에서 복사·붙여넣기 —
cat /proc/meminfo출력을 복사해 상단 입력란에 붙여넣습니다. 가장 간단한 방법입니다. - 일반 파일로 저장 —
cat /proc/meminfo > /tmp/meminfo.txt로 실파일을 만든 뒤 "파일 열기" 로 여세요. 이 때는 정상 동작합니다. - 여러 파일을 한 번에 수집 — 아래 한 줄로 모든 대상을 한 파일에 헤더 포함해 저장합니다. 이 도구는
=== /proc/xxx ===헤더를 자동 인식합니다. for f in meminfo buddyinfo slabinfo interrupts softirqs vmstat \ stat loadavg uptime diskstats swaps lock_stat \ cpuinfo cmdline version modules zoneinfo; do echo "=== /proc/$f ===" cat /proc/$f echo done > /tmp/proc-dump.txt # 네트워크 하위와 sysctl 도 포함하려면 for f in net/dev net/sockstat net/snmp net/netstat net/softnet_stat \ sys/fs/file-nr sys/fs/inode-nr sys/kernel/tainted; do echo "=== /proc/$f ==="; cat /proc/$f; echo done >> /tmp/proc-dump.txt
한계와 주의사항
- 스냅샷 한 장만으로는 추세를 알 수 없습니다. 특히 vmstat 같은 누적 카운터는 두 시점 비교가 훨씬 유용합니다.
- 임계치는 범용 경험치 입니다. 메모리 4 GB 임베디드와 1 TB 서버의 임계치가 같을 수 없으므로, 최종 판단은 도메인 지식으로 보완해야 합니다.
- 파서는 관대 모드 입니다. 커널 버전별 필드 차이를 포용하기 위해 엄격한 스키마 검사를 하지 않습니다. 미지의 필드는 무시되며, 예상치 못한 포맷은 "파싱 불가" 로 빠집니다.
- cgroup v2 의
memory.pressure등 계층별 PSI 는/proc/pressure/*와 동일 포맷이므로 이 도구로 분석 가능합니다.