- Authors

- Name
- Youngju Kim
- @fjvbn20031
- 들어가며 — 숫자의 홍수
- 프로세스 열 읽기
- VIRT, RES, SHR — 메모리 세 값의 함정
- 프로세스 상태 문자
- 로드 애버리지 — CPU 사용률과 다르다
- 미터의 색깔
- 좀비 프로세스의 정체
- 카피 온 라이트와 RES의 착시
- 실전 진단 레시피
- 마치며
- 참고 자료
들어가며 — 숫자의 홍수
리눅스 서버에서 htop이나 top을 처음 열면 숫자와 색깔의 홍수에 압도됩니다. 대부분은 CPU와 메모리 퍼센트만 대충 보고 나머지는 무시하지만, 그 숫자 하나하나에는 시스템의 상태를 진단하는 데 필요한 정보가 담겨 있습니다. 최근 해커뉴스(Hacker News) 상단에 다시 오른 페테리스 니키포로프스(Pēteris Ņikiforovs)의 명문 해설 "Explanation of everything you can see in htop"이 이 주제를 다시 조명한 것을 계기로, 이 글에서는 그 필드들을 하나씩 뜯어보겠습니다.
프로세스 열 읽기
프로세스 목록의 각 열이 무엇을 뜻하는지부터 봅시다.
- PID: 프로세스 ID. 프로세스가 시작될 때 부여되는 고유 번호입니다.
- USER: 프로세스의 소유자. 그 프로세스를 실행한 사용자입니다.
- PRI와 NI: 우선순위(priority)와 나이스(nice) 값입니다. 관계는
PR = 20 + NI로 표현됩니다. 나이스 값은 -20(가장 높은 우선순위)부터 19(가장 낮은 우선순위)까지이며, 나이스가 낮을수록 CPU를 더 많이 배정받습니다. 대략적인 어림으로, 나이스 한 단계마다 약 10%의 CPU 시간이 이동한다고 봅니다. - VIRT / RES / SHR: 메모리 관련 세 값이며 아래에서 따로 다룹니다.
- S: 프로세스 상태(state)이며 역시 아래에서 다룹니다.
- %CPU: CPU 사용률입니다.
- %MEM:
RES / 전체 RAM로 계산되는 메모리 사용률입니다. - TIME+: 프로세스가 지금까지 누적으로 사용한 CPU 시간입니다.
VIRT, RES, SHR — 메모리 세 값의 함정
메모리 열은 가장 자주 오해되는 부분입니다. 세 값의 의미가 완전히 다릅니다.
- VIRT (가상 메모리): 프로세스가 확보한 전체 가상 주소 공간입니다. 여기에는 실제로 쓰지 않는 영역, 공유 라이브러리, 메모리 맵 파일, 스왑으로 밀려난 페이지까지 모두 포함됩니다. 그래서 VIRT는 대개 부풀려져 있고, 실제 메모리 사용량의 지표로는 거의 쓸모가 없습니다.
- RES (상주 메모리): 스왑되지 않고 실제 물리 RAM에 올라와 있는, 프로세스가 실제로 쓰고 있는 메모리입니다. "이 프로세스가 지금 RAM을 얼마나 먹고 있나"를 알고 싶다면 이 값을 봐야 합니다.
- SHR (공유 메모리): 다른 프로세스와 공유될 수 있는 메모리입니다. 대표적으로 공유 라이브러리가 여기에 해당합니다.
여기서 중요한 실무 교훈이 하나 나옵니다. 메모리를 많이 먹는 프로세스를 찾을 때는 VIRT가 아니라 RES 기준으로 정렬해야 한다는 것입니다. VIRT로 정렬하면 실제로는 메모리를 별로 안 쓰는데 주소 공간만 크게 잡은 프로세스가 맨 위에 올라와 오판하기 쉽습니다.
프로세스 상태 문자
S 열에는 한 글자로 된 프로세스 상태가 표시됩니다. 각 문자의 의미는 다음과 같습니다.
R— 실행 중이거나 실행 대기(runnable). CPU에서 돌고 있거나 차례를 기다리는 상태입니다.S— 인터럽트 가능한 수면(interruptible sleep). 어떤 이벤트를 기다리며 잠들어 있지만 시그널로 깨울 수 있습니다. 평상시 대부분의 프로세스가 이 상태입니다.D— 인터럽트 불가능한 수면(uninterruptible sleep). 보통 디스크 입출력을 기다리는 상태이며, 시그널로도 깨울 수 없습니다.Z— 좀비(zombie). 종료되었지만 부모가 아직 거둬가지 않은 상태입니다.T— 작업 제어 시그널로 정지된 상태(예: Ctrl+Z).t— 디버거/트레이서에 의해 정지된 상태입니다.
로드 애버리지 — CPU 사용률과 다르다
가장 널리 오해되는 지표가 로드 애버리지(load average) 입니다. 흔히 "CPU 사용률"과 같다고 생각하지만 그렇지 않습니다.
첫째, 로드 애버리지는 단순 평균이 아니라 지수 감쇠 이동 평균입니다. 1분, 5분, 15분 세 개의 값이 표시되며, 최근 값에 더 큰 가중치를 둡니다. 1분 값은 대략 지난 1분의 부하를 63%, 그 이전을 37% 정도로 섞은 값입니다.
둘째, 그리고 더 중요한 점 — 로드는 실행 중인(R) 프로세스뿐 아니라 인터럽트 불가능한 수면(D) 상태의 프로세스도 함께 셉니다. 이 때문에 로드가 높다고 반드시 CPU가 바쁜 것은 아닙니다. 디스크나 네트워크 입출력을 기다리는 프로세스가 많아도 로드는 치솟습니다.
셋째, 로드는 코어 수를 기준으로 해석해야 합니다. N개의 코어를 가진 머신에서 로드가 N이면 대략 100% 활용 상태입니다. 코어가 4개인데 로드가 4라면 포화 상태이고, 코어가 8개인데 로드가 4라면 절반만 쓰이는 셈입니다.
이 세 가지를 종합하면 강력한 진단 규칙이 나옵니다. 로드는 높은데 %CPU는 낮다면, 십중팔구 입출력 대기(I/O wait) 입니다. 이때는 D 상태의 프로세스를 찾아보는 것이 문제 해결의 출발점입니다.
미터의 색깔
htop 상단의 막대 미터도 색으로 정보를 전합니다.
- CPU 미터: 파란색은 낮은 우선순위(나이스 값이 양수인) 스레드, 초록색은 일반 우선순위 스레드, 빨간색은 커널 스레드를 나타냅니다. (htop은 이 밖에도 가상화나 입출력 대기 등을 더 세분해 표시하기도 합니다.)
- 메모리 미터: 초록색은 실제로 쓰이는 메모리(used), 파란색은 버퍼(buffers), 주황색은 캐시(cache)입니다.
여기서 버퍼와 캐시를 "쓰이는 메모리"로 착각하지 않는 것이 중요합니다. 버퍼와 캐시는 커널이 성능을 위해 잠시 빌려 쓰는 영역이며, 애플리케이션이 메모리를 필요로 하면 즉시 반납됩니다. 그래서 실제로 주목해야 할 값은 "used"가 아니라 가용 메모리(available) 입니다. 리눅스에서 "메모리가 거의 다 찼다"는 화면이 대개 문제가 아닌 이유가 이것입니다. 캐시로 채워진 메모리는 필요할 때 비워질 수 있는, 사실상 여유 메모리입니다.
좀비 프로세스의 정체
좀비(Z) 프로세스는 자주 오해됩니다. 몇 가지 사실을 정리하겠습니다.
좀비는 이미 죽은 프로세스입니다. 실행을 마쳤지만, 부모 프로세스가 그 종료 상태를 아직 거둬가지(reap) 않아 프로세스 테이블에 항목만 남아 있는 상태입니다. 그래서 좀비는 메모리를 전혀 소비하지 않습니다. 오직 프로세스 테이블의 슬롯 하나만 차지할 뿐입니다.
또한 좀비는 죽일 수 없습니다. 프로세스를 종료시키려면 시그널을 보내야 하는데, 시그널은 살아 있는 프로세스만 받을 수 있습니다. 이미 죽은 좀비에게 kill -9를 보내도 소용이 없습니다. 좀비가 사라지는 유일한 길은 부모가 그것을 거둬가는 것입니다. 만약 부모가 먼저 죽으면, 좀비는 init(PID 1)에게 입양되고 init이 대신 거둬갑니다.
즉 좀비가 몇 개 보인다고 당황할 필요는 없습니다. 좀비가 계속 쌓인다면 그것은 좀비 자체가 문제라기보다, 자식을 제대로 거둬가지 않는 부모 프로세스의 버그를 가리키는 신호입니다.
카피 온 라이트와 RES의 착시
한 가지 미묘한 현상을 덧붙이겠습니다. 프로세스가 fork로 자식을 만들면, 리눅스는 카피 온 라이트(copy-on-write) 를 씁니다. 부모와 자식이 같은 물리 메모리 페이지를 공유하다가, 어느 쪽이 쓰기를 할 때에만 그 페이지를 복제합니다.
이 때문에 htop에서 부모와 자식이 각각 전체 RES를 통째로 표시할 수 있습니다. 겉보기에는 메모리를 두 배로 쓰는 것 같지만, 실제 물리 메모리는 공유되고 있어 합계가 그만큼 크지 않습니다. 프로세스를 많이 fork하는 프로그램의 메모리를 볼 때 이 착시를 염두에 두어야 합니다.
실전 진단 레시피
지금까지의 내용을 실제 문제 해결에 적용하면 다음과 같습니다.
- "로드는 높은데 CPU는 한가하다" → 입출력 대기입니다.
D상태 프로세스를 찾고, 디스크나 네트워크 병목을 의심합니다. - 메모리를 먹는 범인 찾기 → VIRT가 아니라 RES 기준으로 정렬합니다.
- 폭주하는 스레드 찾기 → htop에서 스레드 표시를 켜고
%CPU가 지속적으로 높은 항목을 봅니다. - "메모리가 꽉 찼다" → used가 아니라 available을 봅니다. 캐시로 찬 것은 문제가 아닙니다.
이 도구들을 브라우저에서 직접 만져보고 싶다면 이 사이트의 리눅스 터미널이나 웹 터미널을, 커널 파라미터가 이런 동작에 어떻게 관여하는지 살펴보고 싶다면 커널 파라미터 탐색기를 함께 열어보면 좋습니다.
마치며
htop과 top의 숫자들은 처음엔 암호처럼 보이지만, 각 필드의 의미를 알고 나면 시스템의 상태를 읽는 강력한 진단 도구가 됩니다. 특히 VIRT와 RES의 차이, 로드가 입출력 대기를 포함한다는 사실, 캐시가 사실상 여유 메모리라는 점 — 이 세 가지만 제대로 이해해도 서버 문제 진단의 절반은 해결됩니다.