아무것도 몰라요

리눅스

Kernel Memory Allocation

telomere37 2021. 6. 8. 14:49

0. 도입

프로그램이 실행이 되면 프로세스가 되어 메모리에 올라간다. 메모리 상의 일정 영역을 code, data, stack, heap으로 나누어 프로세스가 실행하는데 필요한 행동을 하게 된다. 이 중 code영역은 실제 코드가 올라가는 영역이고 data영역은 전역 변수들이 들어간다. stack에는 단순 변수, 함수의 return address 등이 들어가고 heap은 malloc과 같은 동적 할당을 하여 접근할 수 있게 된다. 현재 존재하는 거의 모든 컴퓨터는 가상 메모리를 사용하고 있기 때문에, 이러한 process의 memory space가 항상 실제 메모리 위에 올라가 있지는 않다. 여기서 궁금증이 생긴다. virtual memory를 사용하는 컴퓨터는 모든 process의 page가 swap의 대상이 될 수 있다. 그렇다면 커널 영역은? kernel memroy space는 물리적으로 고정이 되어 있을까? 각각의 process의 virtual address에서 사용하는 커널 영역의 코드는 가상 영역일까? 찾아보니 일정 부분은 절대 swap out이 안되기도 하고, 특정 부분은 swap의 대상이 된다고 한다. 뭐.. process를 switch 해주거나 page swap 등을 해주는 부분들이 이에 해당하지 않을까? 

이야기가 길어졌지만, 사실 오늘 공부할 내용은 앞의 내용과 거의 상관없다. 오늘은 커널 영역에서 동적인 메모리를 얻기 위해서 할 수 있는 command에 대하여 알아볼 것이다. 커널 영역은 user address space보다 민감하고 위험하다. 함부로 malloc을 사용해서는 안된다! 그렇다면 어떤 명령어를 사용하는 것이고, 그 기초에는 어떤 방식으로 실행이 되는 것일까?

 

1. High level memory allocation

우선 high level의 memory allocation에 대하여 알아보자. 우선 커널 영역에서의 동적 할당은 다음과 같은 성질을 요구한다.

   1) 미리 정의된 크기의 단위로 할당이 된다. (page size)

   2) 가상 메모리를 할당하는 User level의 memory와는 다르게, 실제 물리적인 memory를 할당함으로 항상 성공한다는 보장이 없다.

   3) DMA의 경우 연속된 물리 주소를 요구할 수 있다.

   4) Interrupt handler와 같이 memory allocation 도중에 sleep을 해서는 안되는 경우가 있다.

이러한 요구 사항들을 충족하기 위해 커널이 사용하는 함수를 알아보도록 하자.

 

1.1)kmalloc(), kfree()

  • 물리적으로 연속적인 memory space를 할당받을 때 사용한다. 
  • 최대 PAGE_SIZE * 32(128kb, page size=4kb) 만큼의 크기를 한 번에 할당받을 수 있다. (이후에는 최대 4MB
  • 빠르고 간단하다. 
  • <linux/slab.h>
  • Flag에 들어가는 내용을 통해 atomic 여부를 설정할 수 있다.
    GFP_KERNEL: 충분한 memory가 없는 경우 sleep이 가능하다, 따라서 항상 할당된 메모리를 반환한다.
    GFP_ATOMIC: 충분한 memory가 없는 경우 NULL을 반환한다, 따라서 slepp을 하지 않는다
    GFP_DMA: DMA전용 영역을 할당한다.

1.2)vmalloc(), vfree()

  • 가상 메모리 상에서 연속적인 Memory space를 할당받을 때 사용한다.
  • 크고 연속적인 buffer를 할당할 때 사용한다.
  • 느리고, sleep이 가능하기 때문에 interrupt context(interrupt handler)에서 사용할 수 없다.
  • <linux/vmalloc.h>

2. Low level memory allocation

위에서 제시한 두 개의 함수들은 User에서 사용하는 malloc과 형태가 매우 비슷하지만 실제로 아래에서 하는 일은 다르다. 하지만 결국 이 함수들의 가장 아래의 단으로 내려가면 page단위로 할당을 받게 된다. 그 경우 사용하는 것이 바로 get_free_page이다.

 

2.1) get_free_page()

  • 기본적으로 page단위의 allocation을 한다.
  • version 2.4 까지는 <linux/mm.h>, version 2.6부터는 <linux/gfp.h>
  • Variations
    > get_zeroed_page(unsigned int flags) : page를 0으로 채움
    > __get_free_page(unsigned int flags) : page를 할당받기, 반환 값은 {struct * page}
    > alloc_page(flags) : __get_free_page와 같음
    > __get_free_pages(unsigned int flags, unsigned int order): 여러 개의 page할당, 2^order만큼 할당받는다. 반환 값은 첫 page의 시작 주소
    > alloc_pages(flags, order) : __get_free_pages와 같음
  • unsigned int order의 계산을 편리하게 하기 위하여 'get_order()' 메크로를 사용한다

2.2) free page

  • Variations
    > __free_pages(struct page *page, unsigned int order)
    > free_page(unsigned long addr)
    > free_pages(unsigned long addr, unsigned int order)
  • 인자로 주소가 들어오는 함수와 structure가 들어오는 함수를 구분해야 된다.

3) Buddy system & SLAB Layer

이 부분은 제대로 된 지식이 없지만, 어느정도 혼자 이해한 수준에서 기록해보겠다. Buddy system은 하나의 큰 memory block을 반으로 나누는 것을 반복하여, 수행해야 되는 작업에 최적화된 memory를 할당하는 것이다. 이는 낭비되는 메모리 공간을 최소화한다는 장점을 가지고 있다. 따라서 실제로 요청한 메모리의 크기보다 더 큰 영역이 할당이 될 수 있다. external fragmentation을 줄이는 대신 적당한 internal fragmentation을 수용하는 것이라고 이해했다. Slab이란 물리적으로 연속적인 몇 개의 page로 미리 할당된 메모리라고 생각할 수 있다. 

나의 선생님들 중 한분이신 'geeksforgeeks'에 추가적인 설명이 나와있다.

https://www.geeksforgeeks.org/operating-system-allocating-kernel-memory-buddy-system-slab-sys tem/

'리눅스' 카테고리의 다른 글

IPMI ssh로 접속하기  (0) 2021.09.23
Timer Management  (0) 2021.06.08
Device Control Method  (0) 2021.04.21
Cross Development Environment(교차 개발 환경)  (0) 2021.03.12
[linux kernel] CFS Scheduler에서 VR(T) 조정(fork)  (0) 2021.02.21