- 출처: https://docs.kernel.org/admin-guide/mm/concepts.html
Concepts overview — The Linux Kernel documentation
The memory management in Linux is a complex system that evolved over the years and included more and more functionality to support a variety of systems from MMU-less microcontrollers to supercomputers. The memory management for systems without an MMU is ca
docs.kernel.org
Virtual Memory Primer
컴퓨터 시스템에서 물리 메모리는 제한된 자원이다. 물리 메모리는 반드시 연속적이어야 하지는 않으며 몇 개의 주소 범위로 접근될 수 있다. 또한 다른 CPU 아키텍처나 같은 아키텍처라 할지라도 다른 구현세부사항에 따라 주소 범위를 정의하는 관점이 다를 수 있다.
이런 사실 때문에 직접적으로 물리 주소를 다루는건 꽤 복잡하므로 이를 회피하기 위해 가상 메모리 개념이 필요하다. 가상 메모리는 어플리케이션 소프트웨어로 부터 물리 메모리의 세부사항을 추상화해주어서 물리 메모리에는 필요한 정보만 담을 수 있게 해주고, 프로세스간 데이터 공유의 제어 및 보호 메커니즘을 제공해준다.
CPU 가 시스템 메모리로 부터(혹은 메모리로) 읽는(혹은 쓰는) 명령어를 디코딩할 때 명령어에 인코딩 되어 있는 가상 메모리를 메모리 컨트롤러가 이해할 수 있는 물리 메모리로 변환한다.
물리 시스템 메모리는 페이지로 나눌 수 있다. 각 페이지의 크기는 아키텍처에 따라 다르다. 일부 아키텍처들은 여러 개의 지원하는 값에서 페이지 크기를 선택할 수 있도록 허용하기도 한다.
각 물리 메모리 페이지는 1개 이상의 가상 페이지로 맵핑된다. 이런 맵핑 정보는 페이지 테이블에 존재한다. 페이지 테이블은 프로그램에서 사용되는 가상 메모리 주소를 물리 메모리 주소로 해석하며, 계층 구조로 되어있다.
페이지 테이블 계층의 최하단 수준에는 소프트웨어에서 사용하는 실제 페이지들의 물리 주소를 포함하고 있다. 상위 수준에는 저수준에 있는 페이지의 물리 주소를 포함하고 있다. 페이지 테이블 최상단에 대한 포인터는 레지스터에 존재한다. CPU가 주소 변환을 할 때 페이지 테이블의 최상단에 접근하기 위해 이 레지스터를 사용한다.
Huge Pages
주소 변환시 몇 번의 메모리 접근을 해야하는데 이 과정은 CPU 속도와 비교해서 상대적으로 느린 작업이다. 주소 변환시 프로세서 사이클의 낭비를 회피하기 위해 CPU는 TLB(Translation Lookaside Buffer) 라는 곳에 이런 변환에 대한 캐싱 정보를 유지한다. 대게 TLB 는 희소 자원이며 대용량 메모리 working set 어플리케이션은 TLB miss로 인해 성능 저하를 겪게 된다.
많은 최신 CPU 아키텍처 들이 페이지 테이블의 고수준에서 메모리 페이지를 직접 맵핑하는것을 허용한다. 예를 들어 x86 의 경우 페이지 테이블의 2번째와 3번째 계층에서 2M ~ 1G 페이지 항목을 사용하여 맵핑할 수 있다. Linux 에서는 이를 Huge Pages 라고 한다. Huge pages 를 사용하면 TLB 에 대한 압력을 상당히 줄일 수 있고, TLB hit 율을 향상시켜서 전반적인 시스템 성능이 향상된다.
Linux 에서는 물리 메모리를 huge pages 와 맵핑하는 2가지 매커니즘이 있다. 첫번째는 HugeTLB 파일 시스템 혹은 higetlbfs 이다. 이는 RAM 을 백업 저장소로 사용하는 pseudo 파일 시스템이다. 이 파일시스템에서 생성된 파일들의 경우 데이터가 메모리에 상주하고 huge pages 를 통해 맵핑된다.
또 다른 하나는 Transparent HugePages 혹은 THP 라고 하는 매커니즘이다. 사용자와 시스템 관리자가 huge pages 에 의해 맵핑되어야 하거나 맵핑될 수 있는 지를 구성해야하는 hugetlbfs 와 다르게 THP는 이런 맵핑을 투명하게 관리한다.
Zones
종종 하드웨어는 접근할 수 있는 물리 메모리의 범위에 제약을 가한다. 어떤 장치들은 DMA 를 수행할 수 없어서 모든 어드레스메모리에 접근할 수 없다. 또는 물리 메모리의 크기가 가상 메모리의 최대 주소 크기를 초과하여 해당 메모리에 접근하기 위해 추가 조치를 요구하기도 한다. Linux 는 메모리 페이지들을 zones 으로 그룹화한다. 예를 들어 ZONE_DMA 는 DMA 를 위해 장치에서 사용되는 메모리를 포함하며, ZONE_HIGHMEM은 커널의 주소공간에 영구적으로 맵핑되지 않는 메모리들을 포함하고, ZONE_NORMAL 은 일반적인 페이지 주소들이 포함된다.
메모리 zones의 실제 레이아웃은 하드웨어에 따라 다르다. 모든 아키텍처가 모든 영역을 정의하는것은 아니고 DMA 에 대한 요구사항은 플랫폼마다 다르다.
Nodes
많은 멀티 프로세서 머신은 NUMA(Non-Uniform Memory Access) 시스템이다. 이런 시스템에서 메모리는 여러 개의 bank 로 구성되며, 프로세서와의 거리에 따라 접근 지연시간이 달라진다. 각 bank 는 node 라고 하며 각 node에 대해 Linux 는 독립적인 메모리 관리 서브시스템을 구축한다. 노드는 자체 zones 세트, 사용 및 미사용 페이지 목록, 다양한 통계 지표를 갖고 있다.
Page Cache
물리 메모리는 휘발성이며 일반적으로 파일로 부터 읽은 후 메모리로 데이터를 집어넣는다. 파일을 읽을때마다 추후에 읽을 때 디스크 접근시 오래 걸리므로 이를 회피하기 위해 데이터는 page cache 로 들어간다. 비슷하게 파일에 쓸 때 page cache 에 데이터가 저장되며 이후 백업 장치로 반영된다. 기록된 데이터는 dirty 로 마킹되며 Linux가 다른 목적으로 재사용한다고 결정하면 갱신된 데이터로 장치의 파일 내용을 동기화하는것을 보장한다.
Anonymous memory
anonymous memory 혹은 anonymous mappings 는 파일 시스템에 의해 지원되지 않는 메모리를 말한다. 이런 맵핑들은 암묵적으로 프로그램의 스택과 힙에서 생성되거나 명시적으로 mmap 시스템 호출에 의한것이다. 대게 anonymous mappings 은 프로그램이 접근하도록 허용된 가상 메모리 영역만 정의한다. 읽기 접근은 0으로 채워진 특수한 물리적 페이지를 참조하는 페이지 테이블 항목을 생성한다. 프로그램이 쓰기를 수행할 때 쓰여진 데이터를 유지하기 위해 물리 메모리 페이지가 할당된다. 페이지는 더티로 마킹되고 만약 커널이 재사용하기로 결정하면 더티 페이지는 스왑(swapped out)된다.
Reclaim
시스템 생명주기동안 물리 page는 다양한 유형의 데이터를 저장하는데 사용된다. 이는 커널의 내부 데이터 구조, 장치 드라이버 사용을 위한 DMA 버퍼, 파일 시스템으로 부터 읽은 데이터, 사용자 공간 프로세스에 의해 할당된 메모리 등이 될 수 있다.
Page 사용 방식에 따라 Linux 메모리 관리에서 다르게 처리된다. 하드 디스크 등 다른곳에서 사용될 수 있는 데이터를 캐싱하기 때문에 언제든지 해제되거나, 다시 하드디스크로 swapped out 될 수 있는 page 들을 회수 가능한(reclaimable) page 라고 한다. 회수 가능한 page 들의 가장 일반적인 범주는 page cache와 anonymous memory 이다.
대부분의 경우 내부 커널 데이터를 잡고 있거나 DMA buffer 로 사용되는 page 들은 다른 용도로 재사용될 수 없으며 user에 의해 해제될때까지 남아있다. 이런 page 들을 회수 불가능한(unreclaimable) 이라고 표현한다. 그러나 특정 상황에서 심지어 커널 데이터 구조에 의해 점유되고 있더라도 회수 가능한 경우가 있다. 예를 들어 파일 시스템 메타데이터의 메모리 내부 캐시는 저장 장치로 부터 다시 읽어질 수 있으므로 시스템에 메모리가 부족한 경우 메인 메모리 공간에서 해당 데이터들을 버리는것이 가능하다.
회수 가능한 물리 메모리 page 를 해제하고 다른 목적으로 재사용하는 과정을 회수(reclaim) 이라고 한다. Linux 는 page 들을 시스템 상태에 따라 동기나 비동기로 회수한다. 시스템이 부하상황이 아닌 경우 메모리의 대부분은 여유 상태이며 요청이 할당되면 해제된 page 들에서 즉시 처리된다. 부하가 증가하면 여유 page 들의 양이 점차 줄어들며 특정 임계치에 도달하면 kswapd 데몬이 실행된다. 비동기적으로 메모리 page 들을 스캔하고 만약 page 들이 포함한 데이터가 다른곳에서 사용가능한 경우 page 를 단순히 해제하거나 또는 다시 저장 장치로 보낸다. 메모리 사용량이 증가하여 임계치에 도달하면 직접적으로 회수를 발동시키게 된다. 이런 경우 요청을 충족할 만큼 메모리 page가 회수될때까지 활동이 중단된다.
Compaction
시스템이 실행될 때 작업은 메모리를 할당 및 해제하면서 단편 조각들을 만들게 된다. 비록 가상 메모리가 흩어진 물리 page 들을 가상의 연속적인 범위처럼 사용할 수 있게 해주지만 때로는 큰 연속적인 물리 메모리 공간의 할당이 필요할 수 있다. 예를 들어 장치 드라이버가 DMA 를 위한 큰 버퍼가 필요하거나 또는 THP가 거대한 page를 할당할 때와 같은 경우가 있다. 메모리 compaction 은 단편 조각 이슈를 해결해준다. 이 매커니즘은 메모리 zone의 하위 부분에서 점유된 page 들을 zone의 상위 부분의 여유 page 로 옮겨준다. compaction 스캔이 끝나면 여유 page 들은 zone 의 시작점에서 그룹화되고 큰 연속적인 물리 메모리들의 할당이 가능해진다.
OOM Killer
부하상태의 머신에서는 메모리가 소진될 수 있으며 이때 커널은 동작을 지속할 수 있을 정도의 충분한 메모리를 회수하지 못하는 상태가 될 수 있다. 시스템의 나머지 부분은 살리기 위해 OOM killer를 실행하게 된다.
OOM Killer 는 전반적인 시스템의 상태를 고려하여 희생시킬 작업을 선택한다. 충분한 메모리가 해제되어 일반적인 동작이 가능할 거라고 기대하면서 선택한 작업을 종료하게 된다.
'Concepts > OS' 카테고리의 다른 글
Introduction to Control Group (0) | 2025.03.17 |
---|---|
File System (0) | 2024.11.03 |
Limited Direct Execution (0) | 2024.05.25 |
Process API (0) | 2024.05.15 |
Process Abstraction (0) | 2024.05.05 |
댓글