[Linux Kernel v5.15: Memory] Zone

Merry Berry·2024년 1월 20일
0

Linux Kernel

목록 보기
4/4
post-thumbnail

Introduction of Node & Zone

https://www.iue.tuwien.ac.at/phd/weinbub/dissertationsu16.html

위 NUMA(Non-Uniform Memory Access)에서 동일한 Memory에 접근하는 CPU들을 Node라고 한다. UMA(Uniform Memory Access)에서는 1개의 node로 구성된다.

linux kernel에서는 각 node의 물리 메모리를 Zone이라는 영역으로 나누어 관리한다.

Page Frame Descriptor

page frame에 대한 정보는 struct page에 있으며, 이를 Page Frame Descriptor이라 한다. page frame 각각에 대해 존재하며, 기본 kernel config 기준 최소 56 bytes를 차지한다.
https://elixir.bootlin.com/linux/v5.15.113/source/include/linux/mm_types.h#L70

unsigned long			flags;		// page frame 속성 정보. 각 플래그 정보는 /include/linux/page-flags.h에서 찾을 수 있다.
struct list_head		lru;		// LRU linked list node
struct address_space	*mapping;	// 해당 page frame이 어디에 속해 있는지를 기술하는 구조체 address_space의 포인터
pgoff_t					index;		// mmap mapping 내에서의 offset
unsigned long			private;	// 아무 용도로 사용 (pointer size). 원하는 구조체의 포인터로 casting해서 사용하기도 한다.
atomic_t				_mapcount;	// page table에 매핑된 카운트. page table에서 해당 page frame을 참조 시 1씩 증가한다. (초기 값은 -1). page_mapcount() inline function으로 해당 필드를 읽는다.
atomic_t				_refcount;	// kernel code에서 참조 시 1씩 증가(LRU list 등...), 참조 해제되면 1씩 감소. page 사용 여부를 판단하고, count를 감소시켜 회수하는 방법도 있다.

Zone

Zone은 각 영역에 따라 사용 용도가 다르다.

  1. ZONE_DMA: 0B~16MB까지 접근 가능한 ISA 장치의 DMA 영역 (x86: 0B~16MB)
  2. ZONE_DMA32: 4GB(32bit memory address)까지 접근 가능한 장치의 DMA 영역
  3. ZONE_NORMAL: kernel vertual memory에 direct mapping되는 영역, 대부분의 메모리 할당이 발생 (x86: 최대 0.9GB(896MB), x86-64: 최대 64TB 또는 4PB)
  4. ZONE_HIGHMEM: kernel virtual memory에 direct mapping되지 않는 영역 (x86: 896MB~, x86-64에서는 필요 없음)
  5. ZONE_MOVABLE: memory compaction을 위해 movable한 메모리만을 담는 pseudo zone 영역
  6. ZONE_DEVICE: 비휘발성 메모리를 위한 영역, CPU에서 load & store을 통해 접근 (NVDIMM). Buddy system에서 관리하지 않는다.

Lowmem = ZONE_DMA + ZONE_DMA32 + ZONE_NORMAL

Pseudo Zone 항상 존재하지 않고 필요할 때만 있는 zone

만약 DMA 버퍼를 할당해야 할 경우, 가능한 경우 ZONE_DMA, ZONE_DMA32에서 할당하고, 해당 zone의 메모리 공간이 부족하면 ZONE_NORMAL에서 할당한다.

Node

각 node의 정보는 struct pglist_data로 관리되며, 이들의 포인터 배열 struct pglist_data *node_data[MAX_NUMNODES]를 통해 접근할 수 있다.
page frame 회수는 각 node에서 동작하며, 각 node에는 kswapd kernel thread가 backgroud 상에서 동작한다.
https://elixir.bootlin.com/linux/v5.15.113/source/include/linux/mmzone.h#L800

struct zone		node_zones[];		// 해당 node에 있는 zone
struct zonelist	node_zonelists[];	// page frame 할당을 위한 zone들의 fall-back list
struct page		*node_mem_map;		// 해당 node에 있는 page frame의 array
struct lruvec	__lruvec;				// LRU list들의 head를 저장 (ACTIVE-ANON, INACTIVE-ANON, ACTIVE-FILE, INACTIVE-FILE, UNEVICTABLE)

Fall Back: 원래 동작이 실패할 경우를 위한 대안. node_zonelists는 기존에 할당 받으려던 zone의 메모리가 부족할 경우 다른 zone에서 메모리를 받기 위해 존재한다.

ZONE_HIGHMEM

https://unix.stackexchange.com/questions/42095/high-memory-user-space-and-highmem-kernel-space
32bit architecture에서는 가상 메모리 주소가 0B~4GB까지이다. 보통 이 가상 메모리 영역을 1:3으로 나누어 0B~3GB를 user spcae, 3GB~4GB를 kernel space로 사용하는데, kernel virtual memory space는 물리 메모리와 1대1 mapping(direct mapping)된다.

kernel space와 user space를 나누는 경계를 나타내는 매크로는 PAGE_OFFSET이다.

예를 들어, kernel space의 가장 가운데 영역을 접근하면, 물리 메모리의 가장 가운데 부분에 접근되는 것이다.
그러면 kernel space와 direct mapping되는 물리 메모리의 크기는 1GB여야 한다. 하지만 물리 메모리가 1GB보다 커지게 되면 kernel space와 direct mapping되지 않는 일부 물리 메모리 영역이 생길 것이고, 그렇게 되면 kernel에서 직접 접근할 수 없게 된다.
이를 해결하기 위해 kernel virtual space의 상위 128MB를 Reserved 영역으로 두고, 나머지 kernel space의 896MB는 직접 물리 메모리에 매핑된다. 그리고 할당된 128MB 영역은 direct mapping되지 않는 물리 메모리 영역을 필요할 때 따로 mapping하여 사용한다. 또한 사용이 끝나면 mapping을 해제한다.
위 그림에서 kernel space에 direct mapping되는 영역을 ZONE_NORMAL, 위에 direct mapping되지 않은 영역을 ZONE_HIGHMEM이라 한다. 64bit architecture에서는 virtual address 영역이 매우 넓으므로 ZONE_HIGHMEM이 필요없다.

도움이 될 만한 자료

https://elinux.org/images/b/b0/Introduction_to_Memory_Management_in_Linux.pdf

0개의 댓글