Virtual Memory
가상 메모리 Virtual Memory 는 메인 메모리의 추상화 개념
프로그램 (프로세스) 이 모든 메모리를 전부 독점적으로 사용한다고 착각할 수 있게 만든다
실행할 프로세스의 일부분만 메모리에 올리고,
메모리에 올라가지 않은 나머지는 보조 기억 장치 (일반적으로 하드디스크나 SSD) 에 위치한다
가상 메모리의 핵심은 보조 기억 장치이다, 보조 기억 장치를 마치 메모리처럼 사용하여 실행 중인 프로그램이 요구하는 주소 공간을 확장하여, 실제 메모리가 부족하더라도 보조 기억 장치를 사용하여 동작할 수 있다
1) 보안성 및 안정성
프로그램이 메모리에 간접 접근하며 기본적으로 프로그램 간 메모리가 분리되며
필요한 경우에만 특정 메모리를 서로 공유해 메모리 접근에 대한 오류를 줄인다
2) 개발 용이성
프로그램은 각자 고유한 메모리를 사용하여 실제 메모리 용량과는 무관하게 프로그램을 만들 수 있다
3) 메모리 관리
운영체제는 프로그램이 추상화된 가상 메모리에 대해 별로 사용되지 않는다고 판단되는
메모리의 일부분을 압축하거나 스왑하여 실제 메모리의 공간을 확보한다
🐣 압축이라는 건 할당된 메모리들을 다 모아서 가용 메모리 용량을 늘리는 것, 근데 압축을 하면 오버헤드가 많이 발생해서 비효율적일 수 있다 🐣
페이지 Page 와 프레임 Frame
가상 메모리의 주소 공간은 고정 크기의 페이지 Page 라는 영역으로 분할되어 있다
각 페이지에 해당되는 물리 메모리도 페이지 프레임 Page Frame 이라는 고정 크기의 슬롯의 배열로 분할되어 있고, 프레임 각각은 하나의 가상 메모리 페이지를 저장할 수 있다
📌 페이지는 4096바이트 (64비트) 의 길이를 가지는 가상 메모리의 연속된 영역이고, 페이지는 반드시 page-aligned 된다
페이지의 상위 32비트는 페이지 테이블의 인덱스를 표시하고, 마지막 12비트는 페이지 오프셋이다
프레임은 물리 메모리 상의 연속적인 영역이다, 페이지 사이즈와 동일한 크기로 페이지와 동일하게 정렬되어 있다
📌 include/vm/vm.h 에 정의되어 있는 page 구조체
하나의 페이지는 VM_UNINIT, VM_ANON, VM_FILE 세 가지 종류 중 하나이고
Swap in, Swap out, destroy 등 여러 동작을 수행한다
/* Path - include/vm/vm.h */
/* The representation of "page".
* This is kind of "parent class", which has four "child class"es, which are
* uninit_page, file_page, anon_page, and page cache (project4).
* DO NOT REMOVE/MODIFY PREDEFINED MEMBER OF THIS STRUCTURE. */
struct page {
const struct page_operations *operations;
void *va; /* Address in terms of user space */
struct frame *frame; /* Back reference for frame */
/* Your implementation */
struct hash_elem hash_elem; /* hash_elem 추가 */
/* Per-type data are binded into the union.
* Each function automatically detects the current union */
union {
struct uninit_page uninit;
struct anon_page anon;
struct file_page file;
#ifdef EFILESYS
struct page_cache page_cache;
#endif
};
};
/* Path - include/vm.h */
/* The representation of "frame" */
struct frame {
void *kva; /* Kernel Virtual Address */
struct page *page; /* Page Structure */
};
Supplemental Page Table 보조 페이지 테이블
📌 페이지 테이블을 보조해서, 페이지 폴트 핸들링이 가능하도록 보조한다
보조 페이지 테이블의 역할은 1) 페이지 폴트가 발생했을 때 그곳에 어떤 데이터가 있어야 했는지 알아내기 위해 보조 페이지 테이블에서 폴트가 발생한 가상 페이지 탐색 2) 커널이 프로세스가 종료될 때 어떤 자원을 free (해제) 할지 고르기 위해 보조 페이지 테이블 조사
보조 페이지 테이블은 세그먼트 (조각) 측면 또는 페이지 측면으로 구성할 수 있다 (세그먼트 - 연속된 페이지 그룹)
/* Path - include/vm.h */
/* Representation of current process's memory space.
* We don't want to force you to obey any specific design for this struct.
* All designs up to you for this. */
struct supplemental_page_table {
struct hash spt_hash; /* 해시 구조체 추가 */
};
Handling Page Fault
/* Path - vm/vm.c */
/* Return true on success */
bool
vm_try_handle_fault (struct intr_frame *f UNUSED, void *addr UNUSED,
bool user UNUSED, bool write UNUSED, bool not_present UNUSED) {
struct supplemental_page_table *spt UNUSED = &thread_current ()->spt;
struct page *page = NULL;
/* TODO: Validate the fault */
/* TODO: Your code goes here */
return vm_do_claim_page (page);
}
Page Table
가상 메모리와 물리 메모리의 매핑 정보를 저장한 데이터 구조
프로세스가 사용하는 가상 주소를 실제 물리 주소로 변환하는 데 사용된다
각 프로세스마다 고유한 페이지 테이블이 있으며, 이 데이터 구조는 RAM 의 일부에 저장된다
❓ RAM 에 저장되는 이유
1) 속도 문제 - 프로세스 실행 중 지속적으로 참조되므로 빠른 접근 속도가 필요하다
2) 공간 문제 - CPU or TLB 에 전체 페이지 테이블을 저장하기에 용량이 부족하다
페이지 테이블은 페이지 테이블 엔트리의 배열로 구성되며, 각 엔트리는 하나의 페이지와 대응하는 물리 프레임의 위치 정보를 포함하고 있다, 즉, 각 페이지 테이블 엔트리는 해당 페이지가 물리 메모리에서 어느 프레임에 위치하는지 알려주는 역할을 한다
📌 페이지 테이블을 관리하는 코드는 threads/mmu.c 안에 있다, 아래 함수 외에도 여러 기능의 함수가 있다
/* Path - threads/mmu.c */
/* Looks up the physical address that corresponds to user virtual
* address UADDR in pml4. Returns the kernel virtual address
* corresponding to that physical address, or a null pointer if
* UADDR is unmapped. */
void *
pml4_get_page (uint64_t *pml4, const void *uaddr) {
ASSERT (is_user_vaddr (uaddr));
uint64_t *pte = pml4e_walk (pml4, (uint64_t) uaddr, 0);
if (pte && (*pte & PTE_P))
return ptov (PTE_ADDR (*pte)) + pg_ofs (uaddr);
return NULL;
}
📌 프레임 테이블에는 각 프레임의 엔트리 정보가 담고 있고, 각 엔트리에는 현재 해당 엔트리를 차지하고 있는 페이지에 대한 포인터와 기타 데이터들이 담겨져 있다, 프레임 테이블은 비어있는 프레임이 없을 때 쫓아낼 페이지를 골라준다
프레임 테이블에서 가장 중요한 작업은 사용되지 않은 (free 상태인) 프레임을 획득하는 것이고, free 상태인 프레임이 없다면, 몇몇 페이지들을 프레임에서 쫓아내어 그 프레임을 free 상태로 만들어주어야 한다
페이지 교체 알고리즘
메모리가 부족할 때 메모리에서 교체할 페이지를 선택하는 기준
FIFO (First-In-First-Out): 가장 먼저 메모리에 올라온 페이지 교체
LRU (Least Recently Used): 가장 오랫동안 사용되지 않은 페이지 교체
LFU (Least Frequently Used): 사용 빈도가 가장 낮은 페이지 교체
Translation Lookaside Buffer, TLB
자주 참조되는 가상 주소 - 물리 메모리 주소 변환 정보를 저장하는 하드웨어 캐시
TLB 보다 주소-변환 캐시 Address-Translation Cache 가 더 정확한 명칭이며, 칩의 메모리 관리부 Memory-Management Unit, MMU 의 일부이다
가상 메모리 참조 시, 1) 하드웨어는 먼저 TLB 에 원하는 변환 정보가 있는지를 확인하고
2) 만약 있다면 페이지 테이블을 통하지 않고 변환을 빠르게 수행한다
Page Fault
페이지 테이블에 가상 주소가 있으면 가상 주소를 물리 주소로 변환할 수 있고, 그 가상 주소에 대응하는 물리 주소가 물리 메모리에 존재하지 않는다면 페이지 폴트가 발생한다 🐣 물리 주소에 실제 데이터가 없는 경우 (해당 페이지가 메모리에 로드되지 않은 경우) 🐣
해당 페이지가 없다는 것을 유효 비트로부터 유추해서 페이지 오류 예외를 발생시키며, 페이지 오류 예외는 커널 내에 페이지 오류 예외 핸들러를 호출한다, 이 핸들러는 해당 페이지를 페이징 파일 (또는 스왑 영역) 에서 읽어와 물리 메모리의 비어있는 공간에 적재하고, 페이지 테이블을 업데이트한 후 다시 CPU 의 동작을 재개시킨다
그리고 해당 페이지가 처음 참조될 때 해당 페이지는 메인 메모리에 적재되어 있지 않고 디스크에 적재되어 있기 때문에 첫번째 접근 시도는 무조건 Page Fault 가 발생하게 된다
📌 페이지 폴트가 발생하면 파일 또는 스왑 슬롯에서 페이지를 가지고 와야 한다, 페이지 폴트 핸들러는 아래와 같은 동작을 해야 한다
1) 보조 페이지 테이블에서 폴트가 발생한 페이지 찾기, 만일 메모리 참조가 유효하다면, 보조 페이지 엔트리를 사용해서 데이터가 들어갈 페이지를 찾는다, 만약 Copy-on-write 를 구현한다면 데이터는 페이지 테이블에 없고 페이지 프레임에 들어가 있다, 만약 주소에서 데이터가 없거나, 읽기 전용 페이지에 대해 쓰기를 시도하는 유효하지 않은 접근을 할 때는 프로세스를 종료시키고 프로세스의 모든 자원을 해제한다
2) 페이지를 저장하기 위해 프레임을 획득한다 3) 데이터를 프레임으로 가져온다 4) 폴트가 발생한 가상 주소에 대한 페이지 테이블 엔트리가 물리 페이지를 가리키도록 지정한다 (threads/mmu.c 에 있는 함수 사용)
🐣 Page Fault 와 메모리 누수는 어느 정도 관련이 있다 🐣
Swap Disk
스왑 공간 Swap Space - 디스크에 페이지들을 저장할 수 있는 공간
메모리 페이지를 읽어서 이곳에 쓰고 (swap out) 페이지를 읽어 메모리에 탑재시키기 (swap in) 때문에 스왑 공간이라 불린다
스왑 공간의 입출력 단위는 페이지이고, 운영체제는 스왑 공간에 있는 모든 페이지들의 디스크 주소를 기억해야 한다
메인 메모리에 데이터를 적재하는 것에 한계가 있기 때문에 여유 공간이 부족할 경우, 사용하지 않는 데이터는 디스크의 스왑 영역으로 옮겨진다, 이를 스와핑 Swapping 이라고 부른다
Swap Disk 는 스왑 영역이 위치한 디스크를 가리킨다, 하지만 대부분의 경우 스왑 디스크나 스왑 영역은 같은 개념으로 사용된다
📌 스왑 테이블은 사용 중인 스왑 슬롯과 빈 스왑 슬롯을 추적한다, 미사용된 스왑 슬롯을 골라 프레임에 있는 페이지를 스왑 파티션으로 쫓아낼 수 있다
vm/build 경로에서 pintos-mkdisk swap.dsk --swap-size=n 명령어를 사용하면 pintos 를 실행할 때 swap.dsk 가 자동으로 추가 디스크로 연결된다
프로세스가 시작될 때 실행파일에서 스왑에 곧바로 쓰는 행위는 추천하지 않는다, eviction 에 실제로 필요할 때만 할당되어야 한다
그리고 스왑 슬롯의 내용물이 프레임으로 읽혀 들어오면 그 때 스왑 슬롯을 free 해준다
Lazy Loading
프로세스가 Load 될 때 해당 프로세스를 즉시 물리 메모리에 배정되지 않고, 프로세스가 해당 메모리 영역을 요구할 때 가용한 물리 메모리 영역을 찾아주는 현상
📌 커널이 새로운 페이지 할당을 요청 받으면 아래 vm_alloc_page_with_initializer 함수가 호출된다
페이지 구조체를 할당하고 페이지 타입에 맞는 적절한 초기화 함수를 세팅하면서 새로운 페이지를 초기화하고, 유저 프로그램으로 제어권을 넘긴다, 유저 프로그램이 실행될 때 콘텐츠가 페이지에 접근하게 되면 Page Fault 가 일어나게 된다
/* Path - vm/vm.c */
/* Create the pending page object with initializer. If you want to create a
* page, do not create it directly and make it through this function or
* `vm_alloc_page`. */
bool
vm_alloc_page_with_initializer (enum vm_type type, void *upage, bool writable,
vm_initializer *init, void *aux) {
ASSERT (VM_TYPE(type) != VM_UNINIT)
struct supplemental_page_table *spt = &thread_current ()->spt;
/* Check wheter the upage is already occupied or not. */
if (spt_find_page (spt, upage) == NULL) {
/* TODO: Create the page, fetch the initialier according to the VM type,
* TODO: and then create "uninit" page struct by calling uninit_new. You
* TODO: should modify the field after calling the uninit_new. */
/* TODO: Insert the page into the spt. */
}
err:
return false;
}
Anonymous Page
특정 파일과 연결되어 있지 않고 스왑 공간 (swap space) 에 연결된 영역 - 파일 백업이 필요 없는 데이터를 위한 메모리 관리 방식
프로세스 실행 중 동적으로 생성된 데이터를 저장하는 데 사용된다 ex. Stack, Heap, 익명 메모리 매핑 mmap
📌 이름이 지정된 File-Backed Page 와 달리 이름이 있는 파일 소스를 가지고 있지 않아서 익명이다, 스택과 힙 영역처럼 실행 가능한 파일에서 사용한다
File-backed Page
메모리 페이지가 특정 파일과 연결되어 있는 영역
프로세스의 가상 메모리 공간을 파일에 매핑하여 파일 내용을 메모리에서 직접 읽고 쓸 수 있도록 하는 방식
특징 | Anonymous Page | File-Backed Ma |
파일과의 연결 | 파일과 연결되지 않고, 스왑 공간과 연결 | 실제 파일과 연결 |
초기화 상태 | 0 으로 초기화 | 파일의 내용에 따라 초기화 |
데이터 저장 위치 | 스왑 공간에만 저장 | 메모리 페이지에 매핑되어 파일과 동기화 |
사용 목적 | 스택, 힙, 임시 데이터 저장, 파일 없이 동적 메모리 할당에 사용 | 데이터 저장, 파일 기반 데이터 공유, 읽기 및 쓰기 시 파일과 연동 |
Direct Memory Access
CPU의 간섭 없이 메모리와 장치 간의 입출력 전송을 담당하는 특수 장치
전송할 데이터가 많은 경우 CPU의 부담을 줄이기 위해 이용하며, 데이터 전송이 완료된 이후에는 한 번의 인터럽트만 보내서 데이터가 전송되는 동안 CPU가 다른 작업을 수행할 수 있게 지원한다
'크래프톤정글 > PintOS' 카테고리의 다른 글
[정글] PintOS Project2 #1 Passing the Arguments and Creating a Thread (2) | 2024.11.18 |
---|---|
[정글] PintOS Project1 #3 Priority Scheduling 2/2 (3) | 2024.11.11 |
[정글] PintOS Project1 #2 Priority Scheduling 1/2 (5) | 2024.11.10 |
[정글] PintOS Project1 #1 Alarm Clock (7) | 2024.11.07 |
[정글] 정글 PintOS 주차 퀴즈 (0) | 2024.11.05 |