top 을 통해 살펴보는 프로세스 정보들
- 옵션 없이 입력하면 주어진 Interval 간격(기본 3초)으로 화면을 갱신하면서 정보를 보여준다.
(1) 현재 서버의 시간, 서버가 얼마나 구동되었는지
(2) 몇 명의 사용자가 로그인해 있는지, 시스템의 Load Average는 어느정도인지
- Load Average는 현재 시스템이 얼마나 많은 일을 하고 있는지를 보여주는 데이터
(3) 현재 시스템에서 구동 중인 프로세스의 개수.
(4) 각각의 CPU, Mem, swap 메모리의 사용량.
- swap 메모리가 상단에 있다는 것은 swap 메모리의 사용 여부가 시스템의 상태에 중요한 영향을 끼친다는 뜻으로 해석 가능.
(5) PR, NI, VIRT, RES, SHR, S
- PR : 프로세스의 실행 우선 순위, 즉 다른 프로세스들 보다 더 먼저 실행되어야 하는지의 여부.
- NI : PR을 얼마만큼 조절할 것인지를 결정.
- 기존 PR 값에 NI 값을 더해서 실제 PR의 값을 결정.
- VIRT, RES, SHR : 프로세스가 사용하는 메모리의 양.
- 이를 통해 메모리 누수가 있는 지를 확인할 수 있어 중요한 정보 중 하나.
- S : 프로세스의 상태를 나타내는 정보
- 현재 CPU를 사용하면서 작업하는 상태인지, I/O를 기다리는 상태인지, 아니면 아무 작업도 하지 않는 유휴 상태인지.
※ VIRT, RES, SHR
- VIRT - (보통 프로세스라고 부르는) task가 사용하고 있는 virtual memory의 전체 용량.
- RES - task가 사용하고 있는 물리 메모리의 양.
- SHR - 다른 프로세스와 공유하고 있는 shared memory의 양을 의미.
VIRT는 Task, 즉 프로세스에 할당된 가상 메모리 전체의 크기이며,
RES는 그 중 실제로 메모리에 올려서 사용하고 있는 물리 메모리의 크기,
SHR은 다른 프로세스와 공유하고 있는 메모리의 크기. (라이브러리가 SHR 영역에 포함될 수 있다.)
대부분의 리눅스 프로세스들은 glibc라는 라이브러리를 참조하기 때문에 사용하는 프로세스마다 glibs의 내용을 메모리에 올려서 사용하는 것은 공간 낭비이다. 커널은 이럴 경우를 대비해서 공유 메모리라는 개념을 도입했고, 다수의 프로세스가 함께 사용하는 라이브러리는 공유 메모리 영역에 올려서 함께 사용하도록 구현했다.
VIRT는 실제로는 할당되지 않는 가상의 공간이기 때문에 해당 값이 크다고 해도 문제가 되진 않는다. 실제 사용하고 있는 메모리는 RES 영역이기 때문에 메모리 점유율이 높은 프로세스를 찾기 위해서는 RES 영역이 높은 프로세스를 찾아야 한다.
※ VIRT와 RES 그리고 Memory Commit의 개념
왜 메모리는 VIRT와 RES로 구분되어 있을까? 둘 다 프로세스가 사용하는 메모리를 표현하는 것이지만 차이점이 있다.
VIRT로 표현되는 가상 메모리는 프로세스가 커널로부터 사용을 예약 받은 메모리이다. 프로세스는 malloc( )과 같은 시스템 콜로 자신이 필요로 하는 메모리의 영역을 할당해 줄 것을 요청한다. 이에 대해 커널은 가용한 공간이 있다면 성공 메시지와 함께 해당 프로세스가 사용할 수 있도록 가상의 메모리 주소를 전달해준다.
하지만 기억해야 할 것은 이때에도 물리 메모리에 해당 영역이 할당된 상태는 아니라는 점.
이런 동작 방식을 Memory Commit 이라고 하며, 커널 파라미터 중에 vm.overcommit_memory를 통해서 동작 방식을 정의할 수 있다.
- vm.overcommit_memory=0
- (Default) overcommit 할 수 있는 최댓값은 page cache와 swap 영역 그리고 slab reclaimable 을 합한 값
- vm.overcommit_memory=1
- 무조건 Commit을 진행.
- vm.overcommit_memory=2
- 제한적으로 Commit을 진행. 메모리 누수가 있는 프로세스가 있다면 시스템 응답 불가 현상을 일으킬 수 있다.
그 후 프로세스가 할당받은 메모리 영역에 실제로 쓰기 작업을 하면 Page fault가 발생하며, 그제서야 커널은 실제 물리 메모리에 프로세스의 가상 메모리 공간을 매핑한다. 이것은 Page Table이라고 불리는 커널의 전역 변수로 관리된다. 그리고 이렇게 물리 메모리에 바인딩된 영역이 RES로 계산된다.
※ VIRT는 malloc( ) 등의 시스템 콜을 사용하면 늘어나게 되는데, 한도 끝도 없이 늘어나게 될까?
할당 받고 사용한 메모리는 RES 영역으로 계산이 되고, 이것은 물리 메모리와 관련이 있기 때문에 더 이상 줄 수 있는 메모리 영역이 없다면 swap을 사용하거나 OOM으로 프로세스를 죽이는 등의 방법으로 메모리를 확보하게 될 것이다. 그렇다면 VIRT와 같이 실제 사용하지 않는 영역의 경우는 어떻게 될까? 실제로 사용하지 않기 때문에 무한대로 할당을 받을 수 있는 걸까?
- 이 동작은 커널 파라미터 중 vm.overcommit_memory 파라미터에 의해 결정된다.
※ Memory Commit
프로세스는 자신만의 작업 공간이 필요하고 그 공간은 메모리에 존재한다. 프로세스가 커널에 필요한 만큼의 메모리를 요청하면 커널은 프로세스에 사용 가능한 메모리 영역을 주고 실제로 할당은 하지 않지만 해당 영역을 프로세스에 주었다는 것을 저장해 둔다. 이 일련의 과정을 Memory Commit 이라 부른다.
※커널은 프로세스의 메모리요청에 즉시 할당하지 않고 Memory Commit 과 같은 기술을 써서 요청을 지연시키는 이유
가장 큰 이유는 fork( )와 같은, 새로운 프로세스를 만들기 위한 콜을 처리해야 하기 때문.
fork( ) 시스템 콜을 사용하면 커널은 현재 실행 중인 프로세스와 똑같은 프로세스를 하나 더 만들게 되는데, 대부분은 fork( ) 후 exec( )시스템 콜을 통해서 전혀 다른 프로세스로 변한다.
Reference
- DevOps와 SE를 위한 리눅스 커널 이야기
- 강진우, DevOps와 SE를 위한 리눅스 커널 이야기, 인사이트, 2017, Chapter01
'OS > Linux Server' 카테고리의 다른 글
[리눅스커널이야기] top 을 통해 살펴보는 프로세스 정보들(2) (0) | 2022.07.26 |
---|---|
[Linux] 01. 운영체제의 구조와 특징 (0) | 2022.05.23 |
[Shell Programming] 10. Backup (0) | 2022.03.17 |
[Shell Programming] 9. Looping (0) | 2022.03.11 |
[Shell Programming] 8. Branching (0) | 2022.03.08 |