메모리가 부족한 것을 어떻게 확인할 수 있는지
부족할 경우에 커널은 어떻게 대처하는지
swap 영역
물리 메모리가 부족할 경우를 대비해서 만들어 놓은 영역
비상용으로 확보해 놓은 메모리 공간
하지만 디스크의 일부분을 메모리처럼 사용하기 위해 만들어 놓은 공간이기 때문에 이를 사용하면 시스템 성능 저하가 일어난다.
root@worker1:~# free -k
total used free shared buff/cache available
Mem: 1974564 1117108 302996 2448 554460 679308
Swap: 0 0 0
아주 적은 양이더라도 swap 영역을 사용하고 있다면 메모리가 부족할 수 있다는 의미이기 때문에 어떤 프로세스가 사용하고 있는지 확인이 필요하다.
/proc/<PID>/smaps 파일에 프로세스(PID)가 사용하는 메모리 정보를 저장하고 있다.
root@worker1:/proc/1584# cat smaps | more
55ba9c2d7000-55ba9c2df000 r--p 00000000 08:05 270772 /usr/libexec/col
ord
Size: 32 kB
KernelPageSize: 4 kB
MMUPageSize: 4 kB
Rss: 0 kB
Pss: 0 kB
Shared_Clean: 0 kB
Shared_Dirty: 0 kB
Private_Clean: 0 kB
Private_Dirty: 0 kB
Referenced: 0 kB
Anonymous: 0 kB
LazyFree: 0 kB
AnonHugePages: 0 kB
ShmemPmdMapped: 0 kB
FilePmdMapped: 0 kB
Shared_Hugetlb: 0 kB
Private_Hugetlb: 0 kB
Swap: 0 kB
SwapPss: 0 kB
Locked: 0 kB
THPeligible: 0
VmFlags: rd mr mw me sd
55ba9c2df000-55ba9c2f4000 r-xp 00008000 08:05 270772 /usr/libexec/col
ord
Size: 84 kB
...
프로세스가 사용하고 있는 메모리 영역 중 해당 번지(55ba9c2d7000-55ba9c2df000)에 속한 메모리 영역이 swap 영역에 있는지 아닌지를 확인할 수 있다.
특정 프로세스가 사용하는 전체 swap 영역에 대한 정보가 필요한 경우에는 /proc/<PID>/status 파일을 통해 확인할 수 있다.
root@worker1:/proc/1584# cat status
Name: colord
Umask: 0022
State: S (sleeping)
Tgid: 1584
Ngid: 0
Pid: 1584
PPid: 1
...
VmSwap: 0 kB
...
이번에는 전체 프로세스별로 사용 중인 swap 영역의 크기를 확인해보자.
root@worker1:~# smem -t
PID User Command Swap USS PSS RSS
1340 root bpfilter_umh 0 100 103 532
706 root /usr/sbin/acpid 0 200 205 776
711 root /usr/sbin/cron -f 0 296 306 1184
...
2141 user1 /usr/bin/gnome-shell 0 171624 174553 186560
-------------------------------------------------------------------------------
112 12 0 799836 840713 1159248
버디 시스템
커널이 메모리를 할당하는 과정
커널은 버디 시스템을 통해서 프로세스에 메모리를 할당한다. 버디 시스템은 물리 메모리를 연속된 메모리 영역으로 관리한다. 만약 8KB의 메모리 영역을 요청하면 연속 1개짜리(4KB)를 두 개 주는 것이 아니라 연속 2개까지 영역 하나를 내어준다.
/proc/buddyinfo
root@worker1:~# cat /proc/buddyinfo
Node 0, zone DMA 4 1 2 2 0 1 1 2 0 1 1
Node 0, zone DMA32 531 948 456 300 172 60 25 12 5 2 0
각 행은 2의 배수이며 연속 1개, 2개, 4개의 영역을 의미한다.
DMA 절의 메모리 가용량을 본다면 4KB4개 + 8KB1개 + 16KB2개 + 32KB2개 + 128KB1개 + 256KB1개 + 512KB2개 + 2048KB1개 + 4096KB*1개 이다.
이렇게 가용 영역을 구하여 free 값과 비교해보면 비슷한 수치가 나온다.
메모리 재할당 과정
캐시 메모리 재할당
커널은 메모리를 가용 상태로 두지 않고 캐시 용도로 사용한다. Page Cache, Buffer Cache, inode cache, dentry cache 등이 그 예다. 프로세스가 메모리를 필요로 할 때 메모리가 부족할 수 있고 이때 커널은 캐시 용도로 사용하던 메모리를 사용 해제하고 가용 메모리 영역으로 돌린 후 프로세스가 사용할 수 있도록 재할당한다.
swap을 사용하는 재할당
캐시 용도의 메모리를 해제할 만큼 해제하고도 더 이상 프로세스에 할당해줄 메모리가 없다면 swap을 사용하게 된다. 사용하는 메모리 중 Inactive 리스트에 있는 메모리를 골라서 swap 영역으로 이동시킨다. 그런 다음 해당 메모리 영역을 해제하고 다른 프로세스에 할당한다.
vm.swappiness와 vm.vfs_cache_pressure
vm.swappiness
커널이 얼마나 공격적으로 메모리 영역을 swap 영역으로 옮기느냐를 결정하는 파라미터
메모리가 부족한 상황에서 캐시를 비우느냐 아니면 특정 프로세스의 메모리 영역을 swap 영역으로 옮기느냐를 결정한다.
해당 값이 작을수록 캐시 메모리를 재할당하고, 높을수록 swap 영역을 사용한다.
vm.vfs_cache_pressure
커널이 메모리를 재할당할 때 디렉터리나 inode에 대한 캐시를 재할당하려는 경향을 조절한다.
이는 캐시를 재할당한다고 결정했을 때 PageCache를 더 많이 재할당할지 아니면 디렉터리(dentry cache)나 inode 캐시를 더 많이 재할당할지를 결정한다.
메모리 증설의 포인트
그렇다면 시스템이 swap을 사용한다고 하면 어떻게 대처해야 할까?
메모리 증설? 해야 할 수도, 그렇지 않을 수도 있다!
애플리케이션이 메모리 해제를 하지 않아 메모리 누수가 생긴 것이라면, 메모리를 증설한다고 결국 swap 영역을 사용하기 때문이다.
그렇다면 메모리의 누수가 있는건지, 더 많은 메모리가 필요한건지 어떻게 알 수 있을까?
메모리의 사용량이 선형적으로 증가하는 경우 → 메모리 누수 의심
애플리케이션이 요청을 처리하기 위해 메모리를 할당받고 요청이 끝나면 메모리를 해제해야 하는데, 제대로 해제되지 않으면 사용하는 메모리가 계속해서 늘어난다.
pmap: 해당 프로세스가 사용하는 힙 메모리 영역이 어떻게 변화하는지를 살펴볼 것
gdb: 힙 메모리의 영역에 메모리 덤프를 생성해서 실제 어떤 데이터들이 메모리에 있는지를 확인하고, 이를 통해 어떤 로직에서 문제가 있을지 예측할 것
순간적으로 메모리의 사용량이 폭증하는 경우 → 메모리 사용량 폭증으로 swap을 사용
정리
- 커널은 버디 시스템을 통해서 메모리를 할당하며 버디 시스템은 연속된 메모리 페이지 수를 기준으로 관리한다.
- swap 영역은 메모리가 부족한 경우 프로세스가 사용하는 메모리를 해제해서 저장할 때 사용하며, 이 때문에 불필요한 I/O가 생겨 시스템의 성능이 저하된다.
- swap 영역을 사용한다는 것은 시스템의 메모리가 부족하다는 의미이며, 이는 프로세스의 메모리 누수이거나 실제로 필요한 메모리가 부족하다는 뜻이다.
- swap 영역을 사용할 때에는 어떤 프로세스에서 swap 영역을 사용하는지 정확하게 알 필요가 있으며 smem이라는 툴을 이용해서 빠르게 확인할 수 있다.
- vm.swappiness 파라미터를 통해서 메모리를 재할당할 때 swap을 사용하게 할지 페이지 캐시를 해제하게 할지의 비율을 조절할 수 있다.
- vm.vfs_cache_presseure 파라미터를 통해서 메모리를 재할당할 때 페이지 캐시를 더 많이 해제할지, 디렉터리 캐시나 inode 캐시를 더 많이 해제할지의 비율을 조절할 수 있다.
<참고>
DevOps와 SE를 위한 리눅스 커널 이야기
'Study > Linux' 카테고리의 다른 글
[Linux]TIME_WAIT 소켓 (0) | 2024.04.22 |
---|---|
[Linux]NUMA (1) | 2024.04.18 |
[Linux]free 명령과 메모리 (0) | 2024.04.10 |
[Linux]Load Average와 시스템 부하 (0) | 2024.04.09 |
[Linux]top을 통해 살펴보는 프로세스 정보들 (0) | 2024.04.06 |