프로세스의 상태를 확인하는 방법과 이와 관련된 커널의 내부 동작을 알아본다.
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--
찍어주는 아웃풋에서 주목해볼 곳은 다음과 같다
VIRT는 프로세스가 커널로부터 예약한 가상 메모리의 전체 용량을 의미한다. 프로세스는 malloc()
과 같은 시스템 콜로 자신이 필요로 하는 메모리의 영역을 할당해 줄 것을 요청한다. 요청이 성공했을 때 프로세스는 할당된 메모리를 자신의 영역으로 인식하지만, 이 때 사실 커널은 해당 영역을 프로세스에 주었다는 것을 저장해둘 뿐 실제 물리 메모리에 할당하지는 않는다. 이러한 동작 방식을 Memory Commit
이라고 부른다.
이후 프로세스가 할당받은 메모리 영역에 실제로 쓰기 작업을 할 때 커널은 물리 메모리에 프로세스의 가상 메모리 공간을 매핑한다. 이렇게 물리 메모리에 바인딩된 영역이 바로 RES다. (관련 키워드 Page fault, Page Table)
커널이 Memory Commit과 같은 기술로 메모리 할당을 지연시키는 이유는 fork()와 같은, 새로운 프로세스를 만들기 위한 콜을 처리해야 하기 때문이다. 커널의 vm.overcommit_memory
라는 파라미터를 어떻게 설정하느냐에 따라 Memory Commit의 동작 방식을 세부적으로 설정할 수 있다.
가상 메모리(VIRT)의 양 중 실제로 메모리에 올려서 사용하고 있는 물리 메모리의 크기를 의미한다. 메모리 점유율은 보통 RES를 의미한다.
다른 프로세스들과 공유하고 있는 공유 메모리의 양을 의미한다. glibc와 같이 다수의 프로세스가 공통으로 사용하는 데이터는 공유 메모리 영역에 올려서 함께 사용할 수 있다. 이렇게 하면 각각의 메모리를 절약하는 효과를 볼 수 있다.
프로세스의 상태를 나타낸다. 상태는 다음 중 하나의 값이다.
커널이 프로세스를 스케줄링할 때 사용하는 우선순위를 나타내는 값이다. 우선순위는 값이 낮을 수록 우선순위가 높다.
이 때 스케줄링은 대략 다음과 같은 순서로 이루어진다.
간간히 integer 값이 아닌 RT(RealTime)
라고 표시된 PR 값을 볼 수 있는데, 이는 사용자가 실행한 일반적인 프로세스가 아닌 데몬같은 중요한 프로세스를 뜻한다. RT 프로세스들은 CFS(Completely Fair Scheduling) 스케줄러보다 더 먼지 실행된다.
nice 값이라고 불리며, 우선순위 값을 낮출 때 사용된다. CPU 코어 수가 실행되는 프로세스 수보다 적을 때 nice 값을 통해 프로세스들 중에서 자주 스케줄링될 프로세스를 정할 수 있다.