Process and Kernel

프로세스의 상태를 확인하는 방법과 이와 관련된 커널의 내부 동작을 알아본다.

top

AWS Ubuntu 16.04 AMI (nano)에서 top 명령어로 실행 중인 프로세스들의 상태를 조회한다. 이 때 CPU에 부하를 주기 위해 stress 툴을 통해 5개의 worker를 실행시켰다.

$ apt install stress
$ stress --cpu 5 &
$ top -b -n 1 | more

top - 08:58:09 up 21:41,  2 users,  load average: 5.00, 4.92, 3.69
Tasks: 125 total,   6 running, 119 sleeping,   0 stopped,   0 zombie
%Cpu(s):100.0 us,  0.0 sy,  0.0 ni,  0.0 id,  0.0 wa,  0.0 hi,  0.0 si,  0.0 st
KiB Mem :   498356 total,    75216 free,   127512 used,   295628 buff/cache
KiB Swap:        0 total,        0 free,        0 used.   324340 avail Mem

  PID USER      PR  NI    VIRT    RES    SHR S %CPU %MEM     TIME+ COMMAND
24918 ubuntu    20   0    7480     92      0 R 19.9  0.0   3:15.65 stress
24919 ubuntu    20   0    7480     92      0 R 19.9  0.0   3:15.65 stress
24920 ubuntu    20   0    7480     92      0 R 19.9  0.0   3:15.65 stress
24916 ubuntu    20   0    7480     92      0 R 19.6  0.0   3:15.65 stress
    1 root      20   0   37696   4224   2496 S  0.0  0.8   0:04.21 systemd
    2 root      20   0       0      0      0 S  0.0  0.0   0:00.00 kthreadd
    3 root      20   0       0      0      0 S  0.0  0.0   0:00.28 ksoftirqd/0
    5 root       0 -20       0      0      0 S  0.0  0.0   0:00.00 kworker/0:0H
    7 root      20   0       0      0      0 S  0.0  0.0   0:00.58 rcu_sched
    8 root      20   0       0      0      0 S  0.0  0.0   0:00.00 rcu_bh
    9 root      rt   0       0      0      0 S  0.0  0.0   0:00.00 migration/0
   10 root      rt   0       0      0      0 S  0.0  0.0   0:00.32 watchdog/0
   11 root      20   0       0      0      0 S  0.0  0.0   0:00.00 kdevtmpfs
   12 root       0 -20       0      0      0 S  0.0  0.0   0:00.00 netns
   13 root       0 -20       0      0      0 S  0.0  0.0   0:00.00 perf
   14 root      20   0       0      0      0 S  0.0  0.0   0:00.01 xenwatch
   15 root      20   0       0      0      0 S  0.0  0.0   0:00.00 xenbus
   17 root      20   0       0      0      0 S  0.0  0.0   0:00.01 khungtaskd
   18 root       0 -20       0      0      0 S  0.0  0.0   0:00.00 writeback
   19 root      25   5       0      0      0 S  0.0  0.0   0:00.00 ksmd
   20 root       0 -20       0      0      0 S  0.0  0.0   0:00.00 crypto
   21 root       0 -20       0      0      0 S  0.0  0.0   0:00.00 kintegrityd
--More--

찍어주는 아웃풋에서 주목해볼 곳은 다음과 같다

  • 첫번째 구간(indent로 나뉘어진)에서는 시스템의 총체적인 상태를 보여준다. 프로세스의 총 갯수, 사용중인 CPU와 기타 상태들, 사용중인 메모리와 기타 상태들 등을 확인할 수 있다.
  • 두번째 구간에서는 개별적인 프로세스들의 상태를 확인할 수 있다.
    • PR: 프로세스의 실행 우선순위를 나타낸다.
    • NI: PR의 조정 가능한 조절값을 나타낸다. 보통 실제 우선순위는 PR+NI의 값이다.
    • VIRT, RES, SHR: 프로세스가 사용하는 메모리의 양이 얼마인지 확인할 수 있는 정보들이다.
    • S: 프로세스의 상태를 나타낸다. CPU 사용중, IO 기다림, 유휴 등의 상태가 있다.

프로세스들의 상태들

VIRT

VIRT는 프로세스가 커널로부터 예약한 가상 메모리의 전체 용량을 의미한다. 프로세스는 malloc()과 같은 시스템 콜로 자신이 필요로 하는 메모리의 영역을 할당해 줄 것을 요청한다. 요청이 성공했을 때 프로세스는 할당된 메모리를 자신의 영역으로 인식하지만, 이 때 사실 커널은 해당 영역을 프로세스에 주었다는 것을 저장해둘 뿐 실제 물리 메모리에 할당하지는 않는다. 이러한 동작 방식을 Memory Commit이라고 부른다.

이후 프로세스가 할당받은 메모리 영역에 실제로 쓰기 작업을 할 때 커널은 물리 메모리에 프로세스의 가상 메모리 공간을 매핑한다. 이렇게 물리 메모리에 바인딩된 영역이 바로 RES다. (관련 키워드 Page fault, Page Table)

커널이 Memory Commit과 같은 기술로 메모리 할당을 지연시키는 이유는 fork()와 같은, 새로운 프로세스를 만들기 위한 콜을 처리해야 하기 때문이다. 커널의 vm.overcommit_memory라는 파라미터를 어떻게 설정하느냐에 따라 Memory Commit의 동작 방식을 세부적으로 설정할 수 있다.

RES

가상 메모리(VIRT)의 양 중 실제로 메모리에 올려서 사용하고 있는 물리 메모리의 크기를 의미한다. 메모리 점유율은 보통 RES를 의미한다.

SHR

다른 프로세스들과 공유하고 있는 공유 메모리의 양을 의미한다. glibc와 같이 다수의 프로세스가 공통으로 사용하는 데이터는 공유 메모리 영역에 올려서 함께 사용할 수 있다. 이렇게 하면 각각의 메모리를 절약하는 효과를 볼 수 있다.

S

프로세스의 상태를 나타낸다. 상태는 다음 중 하나의 값이다.

  • D: 디스크 또는 네트워크 I/O를 대기하고 있는 프로세스를 의미한다.
  • R: 실행 중인 프로세스를 의미한다.
  • S: 수면중인 프로세스이다. 언제 어떻게 시그널이 들어올지 모르며 언제든 시그널을 받아서 처리할 수 있는 상태이다.
  • T: traced or stopped. strace 등으로 프로세스의 시스템 콜을 추적하고 있는 상태를 보여준다.
  • Z: 좀비 즉 부모 프로세스가 죽은 자식 프로세스를 의미한다. 좀비 상태의 프로세스는 리소스나 CPU, 메모리를 사용하지 않는다. 하지만 시스템에는 PID의 수가 정해져있기 때문에 좀비 프로세스의 PID가 계속 반환되지 않고 쌓이면 PID 고갈 문제가 발생할 수 있다.

PR

커널이 프로세스를 스케줄링할 때 사용하는 우선순위를 나타내는 값이다. 우선순위는 값이 낮을 수록 우선순위가 높다.

이 때 스케줄링은 대략 다음과 같은 순서로 이루어진다.

Process Scheduling

  • CPU의 Run Queue에 우선순위별로 프로세스가 연결되어 있다.
  • 스케줄러는 우선순위가 높은 프로세스를 꺼내 디스패처에게 넘겨준다.
  • 디스패처는 현재 실행 중이었던 프로세스의 정보를 다른 곳에 저장한 후 넘겨받은 프로세스를 가지고 CPU에 연산을 요청한다.

간간히 integer 값이 아닌 RT(RealTime)라고 표시된 PR 값을 볼 수 있는데, 이는 사용자가 실행한 일반적인 프로세스가 아닌 데몬같은 중요한 프로세스를 뜻한다. RT 프로세스들은 CFS(Completely Fair Scheduling) 스케줄러보다 더 먼지 실행된다.

NI

nice 값이라고 불리며, 우선순위 값을 낮출 때 사용된다. CPU 코어 수가 실행되는 프로세스 수보다 적을 때 nice 값을 통해 프로세스들 중에서 자주 스케줄링될 프로세스를 정할 수 있다.

comments powered by Disqus