Chapter 4 - 메모리 관리(3)

2022. 9. 19. 01:23개발 관련 책 읽기/리눅스 커널 내부구조

가상 메모리 관리 기법

태스크는 자신의 고유한 가상 메모리를 갖는다. 따라서 커널은 태스크의 가상 메모리가 어디에 존재하는지 관리를 해야 한다. 즉,어디에 text영역이 있고 어디에 data영역이 있는지,그리고 어느 영역이 사용 중이며 어느 영역이 사용 가능한지 등의 정보를 알고 있어야 한다. task_struct 자료구조에 가상메모리 관련된 정보가 저장되어 관리된다. task_struct의 mm이라는 필드에 가상메모리 관련 내용이 담겨있다.

 

// include/linux/mm_types.h
struct mm_struct
{
	struct vm_area_struct *mmap;
	struct rb_root mm_rb;
	struct vm_area_struct *mmap_cache;
	atomic_t mm_users, mm_count;
	pgd_t *pgd;
	int map_count;
	struct semaphore mmap_sem;
	mm_context_t context;
	unsigned long start_code, end code, start data;
	unsigned long end_data, start brk, brk, start_stack;
	unsigned long arg_start, arg_end, env_start, env_end;
	unsigned long total_vm, locked_vm def_flags;
	....
		....
}

//pgd_t *pgd;
//include/x86/include/asm/pgtabke_types.h
typedef struct {
	pgdval_t pgd;
}pgd_t;
 

 

mm_struct 자료구조가 관리하는 정보들은 크게 3부분으로 구분할 수 있다.

 

1.태스크를 구성하고 있는 vm_area_struct 구조체들이다. 리눅스 커널은 가상 메모리 공간 중 같은 속성을 가지며 연속인 영역을 region 이라는 이름으로 부른다. (세그먼트=region)

리눅스는 각각의 세그먼트를 vm_area_struct라는 자료구조를 통해 관리한다. 같은 태스크에 속한 vm_area_struct들은 효율적인 관리를 위해 RBTree로 연결되어 있다. mm_struct에는 바로이 트리의 시작을 가리키는 변수인 mm_rb와 최근에 접근한 vm_area_struct를 가리키는 mmap_cache 변수 등이 존재한다.

2.페이지 디렉터리의 시작 주소를 pdg라는 이름의 변수에 유지한다

3.가상 메모리의 구조에 대한 변수들을 갖는다 (start_code,start_data,start_stact 등의 변수)

 

 

mm_struct 그림

 

vm_area_struct는 세그먼트의 시작주소(vm_start),끝 주소(vm_end),그리고 세그먼트의 접근 제어(일기,쓰기,RO 등)등을 기록하는 플래그 등의 변수를 갖는다.또한 이 세그먼트가 실제 실행 파일의 어느 위치에 있는지에 대한 정보를 vm_file와 vm_offset 변수로 관리한다. 이 변수들은 페이지 폴트가 발생했을 때 어떤 파일의 어느 부분을 읽어야 하는지 결정할 때 사용된다.

물리 메모리 관리기법과 마찬가지의 이유로 가상 메모리 역시 고정된 크기의 할당 단위로 관리된다.

리눅스에서는 보통 4KB이며 페이지라고 부른다. 결국 공통의 속성을 갖는 페이지 들이 모여 vm_area를 구성하고, 이를 vm_area_struct라는 자료구조로 관리하는 것이다. 또한 같은 태스크에 속한 vm_area_struct들이 모여 하나의 mm_struct내에서 관리되는 것이다.

 
 
vm_area_struct와 가상 메모리 공간
 

 

가상 메모리와 물리 메모리 연결

가상 메모리와 물리 메로리를 연결을 할 방법이 필요한데 이때 이용되는 것이 페이지 테이블이다.

페이지 테이블은 가상 주소를 물리 주소로 변환하는 주소 변환 정보를 기록한 테이블이다.

페이지 테이블을 통해 가상 주소를 물리 주소로 변환하는 과정을 페이징이라 부른다

 

태스크가 수행하면서 페이지에 접근할 때 해당 페이지가 존재하지 않으면 페이지 폴트가 발생하게 되고 페이지 폴트가 발생하면 트랩이 걸리고 IDT테이블을 거쳐 페이지 폴트 핸들러가 호출된다.

 

페이지 폴트 핸들러는 free 페이지 프레임을 버디로부터 하나 할당받고 실행파일에서 해당 페이지를 읽어 할당받은 페이지 프레임에 읽어다 놓는다.

 

그리고 다시 프로그램은 수행하게 된다.실행파일은 처음 메모리에 적재할 때 모든 페이지를 적재하는 것이 아니다. 수행에 필요한 일부 페이지만 적재하고 다른 페이지들은 실제로 참조될 때 비로소 페이지 폴트 처리 과정을 통해 적재되도록 하는 것이다.

 

이를 요구페이징이라한다

 

리눅스 페이징에 대한 디테일한 정보

http://egloos.zum.com/dojeun/v/317480

 

 

가상메모리의 장점은 무엇일까?

1.물리 메모리 크기와 관계없이 상당히 큰 주소 공간을 사용할 수 있다

2.프로그램의 모든 페이지들을 물리 메모리에 적재할 필요 없이 페이지 폴트를 이용해 요구 페이징을 활용해 메모리를 더 효율적으로 사용할 수 있다.

3.태스크가 특정 영역을 공유하고 싶을 때 단지 페이지 테이블에서 같은 페이지 프레임을 가리키게 하는 것만으로(또는 페이지 테이블 자체를 공유하는 방법으로)공유 메모리를 지원할 수 있다.

 

가상메모리의 단점은 무엇일까?

물리 메모리에 접근하기 위해 주소 변환 과정이 필요하다는 것이다.주소 변환을 위한 많은 오버헤드가 발생할 수 있어 프로그램 수행 시간을 지연시킬 가능성이 있다. 또한 더욱 중요한것은 메모리 접근시간에 대한 예측성을 떨어뜨린다.

 

이러한 문제를 해결하기 위해 대부분의 시스템은 주소 변환 과정의 많은 부분을 하드웨어적으로 처리한다(HAT:Hardware Address Translation 또는 MMU:Memory Management Unit). 또한 TLB같은 페이지 테이블 엔트리 캐시를 사용하여 빠른 주소 변환을 지원한다

 

커널은 어떻게 가상 주소를 물리주소로 변환할까?

 

리눅스 커널은 3~4GB의 가상 주소공간에서 동작한다고 언급한 바 있다.커널도 페이징 단계를 거쳐야 가상 주소를 물리 주소로 변환할 수 있을 것이다.그러자면 우선 mm_struct 안에 있는 pdg(페이지 디렉터리 주소)를 알아야 할것인데, 커널에겐 mm_struct는 물론이고 pgd라는 것도 존재하지 않는다.

 

따라서 리눅스 커널은 자신을 위한 페이지 테이블을 시스템의 부팅 시점에 미리 작성해놓고 이 위치를

swapper_pg_dir이라는 전역변수에 저장해 놓고 사용한다.

 

반응형