htop 화면의 숫자들, 정확히 무슨 뜻일까? Load Average부터 좀비 프로세스까지 완벽 해설

들어가며
서버에 접속하면 습관처럼 htop이나 top을 켜보지만, 화면에 가득한 숫자들이 정확히 무엇을 의미하는지 자신 있게 설명할 수 있는 분은 의외로 많지 않습니다. 이 글은 Ubuntu Server의 htop 화면을 출발점으로, uptime, load average, 프로세스 상태, 메모리 지표가 실제로 어디서 오고 무엇을 뜻하는지 하나씩 추적한 명글(peteris.rocks, 2019)을 정리한 것입니다.
핵심 요약부터 드리자면:
- htop이 보여주는 값 대부분은
/proc(procfs)과/etc/passwd같은 시스템 파일에서 옵니다 - Load average는 CPU 사용률이 아닙니다. 실행 중/대기 중 프로세스에 uninterruptible 상태까지 포함한 지수 감쇠 이동평균입니다
R,S,D,Z같은 상태 코드는 프로세스가 왜 멈췄는지, 왜 죽지 않는지 판단하는 결정적 단서입니다VIRT,RES,SHR은 각각 다른 관점의 메모리라서, 숫자 하나만 보고 "이 프로세스가 메모리를 이만큼 쓴다"고 단정하면 안 됩니다
htop의 값은 어디서 올까: /proc과 strace
htop, top, ps 같은 진단 도구는 마법을 부리는 게 아니라 /proc/<pid>/ 아래의 파일을 읽습니다. 어떤 프로그램이 무슨 파일을 읽는지 궁금하다면 strace로 직접 확인할 수 있습니다.
strace -e open uptime
예를 들어 uptime 명령은 /proc/uptime을 읽습니다. 이 파일의 첫 번째 숫자는 시스템이 켜져 있던 총 시간(초), 두 번째는 idle 상태였던 시간(초)입니다. 재미있는 점은 멀티코어 시스템에서는 idle 시간이 코어별로 합산되어 전체 uptime보다 커질 수 있다는 것입니다.
프로세스 정보도 마찬가지입니다:
/proc/<pid>/cmdline— 실행 명령어 (인자는\0바이트로 구분되어 있어tr '\0' '\n' < /proc/<pid>/cmdline으로 보면 편합니다)/proc/<pid>/cwd— 현재 작업 디렉터리 링크/proc/<pid>/exe— 실행된 바이너리 링크
Load Average, 가장 많이 오해받는 숫자
/proc/loadavg의 첫 세 값은 최근 1분, 5분, 15분의 load average입니다. 그런데 이 값, CPU 사용률과 같은 것이 아닙니다.
Load는 다음을 세는 값입니다:
- 실행 중(running)이거나 실행 대기 중(runnable)인 프로세스
- uninterruptible 상태(
D)의 프로세스 — 보통 I/O 대기
게다가 단순 평균이 아니라 지수 감쇠 이동평균입니다. 1분 load average라고 해서 딱 마지막 60초만 반영하는 게 아니라, 최근 1분에 큰 비중을 두면서 이전 활동도 일부 포함합니다.
대략적인 감 잡기
- 단일 CPU에서 CPU-bound 프로세스 하나 → load
1.00≈ CPU 100% - 2코어 시스템에서 같은 상황 → CPU 사용률 약 50%
- 2코어 시스템의 CPU 100%에 해당하는 load ≈
2.00
다만 이 단순화가 항상 맞지는 않습니다. D 상태 프로세스가 load에 포함되기 때문에, load average는 높은데 CPU 사용률은 낮은 상황(예: NFS 지연, 과도한 swap)이 얼마든지 가능합니다. 순간 CPU 사용률이 궁금하다면 mpstat 1을 쓰세요.
참고로 sleep 30은 sleep 상태라 load를 올리지 않지만, cat /dev/urandom > /dev/null처럼 계속 CPU를 쓰는 작업은 load를 올립니다.
Tasks, PID, 그리고 프로세스 트리
htop 오른쪽 위의 Tasks는 전체 프로세스 수와 실행 중 프로세스 수를 보여줍니다. Linux 커널이 내부적으로 프로세스를 task라고 부르기 때문에 이런 이름이 붙었습니다.
Shift+H— thread 표시 토글 (Tasks: 23, 10 thr)Shift+K— kernel thread 표시 토글 (Tasks: 23, 40 kthr)F5— 프로세스 계층(트리) 보기.ps f,pstree -a와 같은 정보입니다
모든 프로세스에는 PID가 할당되며, PID 1은 부팅 시 시작되는 /sbin/init입니다. bash에서 date를 실행하면 bash가 fork로 자신을 복제하고 exec로 /bin/date를 올린 뒤, parent인 bash가 child의 종료를 wait합니다. 이 parent-child 관계가 프로세스 트리를 이룹니다.
프로세스 사용자와 권한
각 프로세스는 사용자(숫자 UID)에 소유됩니다. /proc/<pid>/status의 Uid 항목에서 확인할 수 있고, id 1000으로 숫자를 이름으로 바꿔볼 수 있습니다. 이름 해석은 /etc/nsswitch.conf 설정에 따라 /etc/passwd, /etc/group(또는 LDAP 등)을 참조합니다.
흥미로운 예외가 setuid입니다. /usr/bin/passwd는 일반 사용자가 실행해도 /etc/shadow에 쓸 수 있는데, 파일 권한에 s 비트가 있어 소유자인 root 권한으로 실행되기 때문입니다. root 소유 setuid 파일은 이렇게 찾을 수 있습니다:
find /bin -user root -perm -u+s
또 하나의 실전 팁: /etc/sudoers에 sudo echo ... >> /etc/sudoers처럼 redirect로 쓰면 실패합니다. echo만 root로 실행되고 append(>>)는 현재 사용자 권한으로 수행되기 때문입니다. sudo tee -a를 쓰거나, 가급적 sudo visudo로 편집하세요. visudo는 저장 전에 문법을 검증해 sudo가 먹통이 되는 사고를 막아줍니다.
프로세스 상태 코드: R, S, D, Z, T
htop의 S 열에 표시되는 상태 코드는 트러블슈팅의 핵심입니다.
| 코드 | 의미 |
|------|------|
| R | 실행 중이거나 run queue에서 대기 중 |
| S | interruptible sleep — 이벤트를 기다리는 중 |
| D | uninterruptible sleep — 보통 I/O 대기 |
| Z | 좀비 — 종료됐지만 parent가 reap하지 않음 |
| T | job control signal로 정지 |
| t | debugger에 의해 정지 |
S: signal로 깨울 수 있는 잠
sleep 1000 같은 프로세스가 여기 해당합니다. kill은 사실 signal을 보내는 시스템 호출이며, 기본 signal은 TERM(종료 요청)입니다. CTRL+C는 bash가 foreground 프로세스에 SIGINT를 보내는 것이고요. 프로그램이 signal handler를 등록했다면 SIGTERM을 받고도 안 죽을 수 있습니다. SIGKILL(9)만이 커널이 프로세스에 응답 기회 없이 강제 종료하는 signal입니다.
D: SIGKILL도 안 통하는 상태
D 상태는 signal로 깨울 수 없습니다. SIGKILL도 signal이기 때문에 kill -9로도 죽일 수 없습니다. 보통 디스크 I/O나 NFS 지연, 메모리 부족으로 인한 과도한 swap 상황에서 나타납니다. 예를 들어 응답 없는 NFS 서버에 mount를 시도하면 /sbin/mount.nfs가 D 상태에 빠집니다. NFS라면 -o intr 옵션으로 interruptible하게 마운트할 수 있습니다.
Z: 좀비는 죽일 수 없다
좀비 프로세스는 이미 종료된 프로세스입니다. 메모리도 안 쓰고 PID만 차지하며, parent가 wait으로 reap해주기를 기다리는 상태죠. 이미 죽었으니 kill이 통하지 않습니다. 잠깐 존재하는 좀비는 정상이지만, 오래 남아 있다면 parent 프로그램의 버그 신호입니다.
VIRT, RES, SHR: 메모리 숫자 세 개의 진실
htop의 메모리 열은 각각 다른 관점을 보여줍니다:
- VIRT — 가상 메모리. 프로세스가 "예약"한 주소 공간으로, 실제 사용량과 거리가 멉니다
- RES — 물리 메모리(RAM)에 실제로 올라간 양
- SHR — 다른 프로세스와 공유 가능한 메모리 (공유 라이브러리 등)
- MEM% — RES 기준 비율
같은 라이브러리를 쓰는 프로세스 여러 개의 RES를 단순 합산하면 공유 메모리가 중복 계산됩니다. 즉, 한 숫자만 보고 실제 메모리 사용량을 단정하기 어렵다는 점을 기억하세요.
마치며
htop은 결국 /proc이라는 창을 예쁘게 보여주는 도구입니다. 화면의 숫자가 이상해 보일 때 strace로 어떤 파일을 읽는지 추적하고, /proc/<pid>/ 아래를 직접 열어보는 습관을 들이면 서버 트러블슈팅 실력이 확실히 한 단계 올라갑니다. 특히 "load는 높은데 CPU는 놀고 있는" 상황에서 D 상태 프로세스를 찾아보는 것, 오늘부터 바로 써먹을 수 있는 팁입니다.