Study/Linux

[Linux]free 명령과 메모리

seomj 2024. 4. 10. 20:04

CPU가 프로세스의 연산 과정에 필요한 리소스라고 한다면, 메모리는 프로세스가 연산할 수 있는 공간을 제공해 주는 리소스라고 할 수 있다. 프로세스는 메모리라는 공간에 자신이 필요한 함수를 넣어 두거나 변수에 값을 저장하거나 하는 방식으로 연산을 위한 공간을 확보하고 작업을 진행한다.


메모리 사용량 확인하기

free

전체 메모리 용량, 사용 중인 용량, buffers와 cached로 명명되는 캐싱 영역의 용량

root@worker1:~# free -m
              total        used        free      shared  buff/cache   available
Mem:           1928        1047          95           2         784         706
Swap:             0           0           0

*-m은 메비바이트(MB) 단위로 출력

  • total: 전체 메모리의 양
  • used: 사용 중인 메모리의 양
  • free: 아직 사용하고 있지 않은 메모리의 양
  • shared: 프로세스 사이에 공유하고 있는 메모리의 양
  • buff/cache: 버퍼 용도로 사용하고 있는 메모리의 양, 커널이 사용하고 있는 영역
  • available: 페이지 캐시라고 불리는 캐시 영역에 있는 메모리 양

 

buffers와 cached 영역

디스크로부터 데이터를 읽거나 사용자의 데이터를 디스크에 저장한다. 하지만 디스크는 매우 느리기 때문에 커널은 메모리의 일부를 캐싱 영역으로 할당하여 사용한다. 즉 한번 읽은 디스크의 내용을 메모리에 저장해두고 디스크로 요청하지 않고 메모리로 요청한다. 이때 사용되는 캐싱 영역을 buffers, cached라고 한다.

 

Page Cache는 파일의 내용을 저장하고 있는 캐시 → cached

Buffer Cache는 파일 시스템의 메타 데이터를 담고 있는 블록을 저장하고 있는 캐시 → buffers

커널이 읽어야 할 데이터가 파일이라면 bio 구조체를 만들고 해당 구조체에 Page Cache 용도로 할당한 메모리 영역을 연결해준다. 그리고 bio 구조체는 디바이스 드라이버와 통신해서 디스크로부터 데이터를 읽어 Page Cahce에 파일의 내용을 채운다.

 

buffers와 cached 영역은 시스템의 I/O 성능 향상을 위해서 커널이 사용하는 영역이다.

 

/proc/meminfo 읽기

free 명령은 각 메모리가 시스템의 어느 부분에서 사용되고 있는지는 자세하게 볼 수 없다.

→ /proc/meminfo를 통해 자세한 메모리 현황을 볼 수 있다.

root@worker1:~# cat /proc/meminfo 
MemTotal:        1974564 kB
MemFree:           68912 kB
MemAvailable:     646276 kB
Buffers:           32504 kB
Cached:           633188 kB
SwapCached:            0 kB
Active:           298700 kB
Inactive:        1066184 kB
Active(anon):       1592 kB
Inactive(anon):   699964 kB
Active(file):     297108 kB
Inactive(file):   366220 kB
...
Dirty:             25728 kB
...
  • SwapCached: swap으로 빠진 메모리 영역 중 다시 메모리로 돌아온 영역
    메모리가 부족해서 swap으로 빠졌던 데이터가 메모리 확보로 다시 돌아가더라도 swap에서 지우지 않는다.
  • Active(anon): anon은 anonymous의 줄임말. 특정 파일의 내용을 저장하고 있는 Page Cache 영역을 제외한 메모리 영역. 주로 프로세스들이 사용하는 메모리 영역을 지칭. 비교적 최근에 메모리 영역이 참조되어 swap 영역으로 이동되지 않을 메모리 영역.
  • Inactive(anon): swap 영역으로 이동될 수 있는 메모리 영역
  • Active(file): 커널이 I/O 성능 향상을 위해 사용하는 영역. buffers와 cached가 여기에 해당.
  • Inactvive(file): I/O 성능 향상을 위해 커널이 캐시 목적으로 사용하고 있는 영역
  • Dirty: I/O 성능 향상을 위해 커널이 캐시 목적으로 사용하는 영역 중 쓰기 작업이 이루어져서 실제 블록 디바이스의 블록에 씌어져야 할 영역

 

Active와 Inactive 구분

/fs/proc/meminfo.c

LRU_ACTIVE와 LRU_INACTIVE의 형태의 pages를 가져온다.

*LRU(Least Recently Used): 페이지를 교체할 때 가장 오랫동안 사용되지 않은 페이지를 교체 대상으로 삼는 기법

 

anon과 file 영역의 메모리는 LRU 기반의 리스트로 관리되고, 이 리스트는 Active와 Inactive로 나뉜다. 자주 사용되는 메모리 영역이 Active 리스트에 남게 되고 자주 사용되지 않는 영역은 Inactive 리스트에 남게 된다.

기본적으로 프로세스가 메모리 할당을 요청하면 해당 메모리의 페이지가 Active 리스트에 연결된다. 메모리 할당에 실패하거나 부족하게 되면 kswapd 혹은 커널 내부에서 try_to_free_pages() 함수를 통해서 LRU 리스트에 있는 메모리들을 확인한다. 이를 통해 Active 리스트에서 Inactive 리스트로 옮겨가거나 Inactive 리스트에서 해제되어 다른 프로세스에게 할당되는 작업이 이뤄진다.

 

slab 메모리 영역

커널이 내부적으로 사용하는 영역

(캐싱 영역 - buffers와 cached / 프로세스 메모리 영역 - anon)

root@worker1:~# cat /proc/meminfo 
...
Slab:             200660 kB
SReclaimable:      90504 kB
SUnreclaim:       110156 kB
...
  • Slab: 커널이 직접 사용하는 영역
  • SReclaimable: Slab 영역 중 재사용될 수 있는 영역
  • SUnreclaim: Slab 영역 중 재사용될 수 없는 영역

 

slabtop을 통해 현재 시스템에서 사용 중인 Slab의 정보를 살펴볼 수 있다.

root@worker1:~# slabtop -o
 Active / Total Objects (% used)    : 644376 / 690014 (93.4%)
 Active / Total Slabs (% used)      : 23951 / 23951 (100.0%)
 Active / Total Caches (% used)     : 120 / 198 (60.6%)
 Active / Total Size (% used)       : 167883.00K / 181726.79K (92.4%)
 Minimum / Average / Maximum Object : 0.01K / 0.26K / 8.00K

  OBJS ACTIVE  USE OBJ SIZE  SLABS OBJ/SLAB CACHE SIZE NAME                   
 90950  83064  91%    0.02K    535      170      2140K lsm_file_cache         
 76398  68341  89%    0.19K   3638       21     14552K dentry                 
 59520  59232  99%    0.12K   1860       32      7440K kernfs_node_cache      
 55312  53125  96%    0.50K   3457       16     27656K kmalloc-512            
 51753  51753 100%    0.10K   1327       39      5308K buffer_head            
 45060  44391  98%    0.62K   3755       12     30040K inode_cache            

 

Slab이 다른 영역과 구분되는 이유

커널 또한 다른 프로세스와 마찬가지로 메모리가 필요하다. 하지만 메모리를 할당해주는 버디 시스템은 4KB의 페이지 단위로 메모리를 할당한다. 커널이 사용하려는 메모리 영역은 좀 더 작고 효율적으로 사용할 수 있어야 한다. 이를 위해 Slab 할당자를 통해서 원하는 메모리 영역을 확보하게 된다.

메모리의 기본 단위인 4KB의 영역을 Slab 할당자는 각각의 목적에 맞는 캐시별로 영역을 할당 받아 사용한다.

가장 많이 사용되는 캐시는 dentry와 inode_cache로, 디렉터리의 계층 관계를 저장해 두는 캐시와 파일의 inode에 대한 정보를 저장해두는 캐시이다.

 

Slab 할당자는 free 명령에서는 used로 계산된다. 간혹 프로세스들이 사용하는 메모리 영역을 모두 더하고도 used와 맞지 않을 경우 Slab 메모리에서 누수가 발생하는 것일 수도 있다.

ex. free 명령을 입력하면 20GB가 넘게 확인되었지만 ps 명령을 통해 확인한 프로세스들의 메모리 사용량을 합한 값은 10GB도 되지 않았다. /proc/meminfo를 확인해보니 Slab 메모리 영역이 27GB 가량을 사용하고 있었다.

Slab 영역 중 어떤 영역이 문제인지 파악하기 위해 slabtop을 통해 확인해보니 dentry cache가 무려 26GB 정도를 사용하고 있었다. 이를 확인한 후 drop cache를 이용한 캐시 영역 강제 플러싱 조치를 취했다.

( echo 2 > /proc/sys/vm/drop_cached )

그러나 일정 기간 후 똑같은 현상이 발생했고 원인을 파악해야 했다. lsof 명령으로 참조하고 있는 디렉터리 정보를 확인해 보았지만 문제가 될 만한 수준은 아니었다. 시간을 두고 slabtop 내용을 살펴보니 dentry cache의 값이 일정한 간격을 두고 증가하는 것을 확인했다. 이는 스케줄링되어 있는 작업이 영향을 끼치는 것이라고 판단했고, cron에 설정해 놓은 curl과 관련된 작업이 영향을 끼친 것으로 확인됐다. curl에서 https에 대한 요청을 처리할 때 사용하는 nss-softokn 라이브러리에 버그가 있었다.

 

정리

  • free 명령으로 볼 수 있는 buffers는 파일 시스템의 메타 데이터 등을 저장하고 있는 블록 디바이스의 블록을 위한 캐시이다.
  • free 명령으로 볼 수 있는 cached는 I/O 작업의 효율성을 위해 한 번 읽은 파일의 내용을 저장하는 데 사용하는 캐시 영역이다.
  • /proc/meminfo에서 보이는 anon 영역은 프로세스에서 사용하는 영역이고, file 영역은 위에서 언급한 I/O 성능 향상을 위해 커널이 캐싱 용도로 사용하는 영역이다.
  • anon과 file 영역은 각각 Active, Inactive라 불리는 LRU List를 통해 관리되고 있으며 각각은 시스템에 해당 메모리 영역에 얼마나 최근에 접근했는지를 기준으로 관리된다.
  • Slab 영역은 커널이 사용하는 캐싱 영역을 의미하며 dentry cache, indoe cache, buffet_head 등 다양한 캐싱 용도로 사용된다.

 

 

 

<참고>

DevOps와 SE를 위한 리눅스 커널 이야기

https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/tree/fs/proc/meminfo.c?h=v5.15.153

'Study > Linux' 카테고리의 다른 글

[Linux]NUMA  (1) 2024.04.18
[Linux]swap  (0) 2024.04.14
[Linux]Load Average와 시스템 부하  (0) 2024.04.09
[Linux]top을 통해 살펴보는 프로세스 정보들  (0) 2024.04.06
[Linux]시스템 구성 정보 확인  (1) 2024.04.03