파일 백업 매핑
Anonymous page와 달리 파일을 기반으로 매핑하는 페이지, 페이지에 담기는 내용은 실제 디스크에 존재하는 파일의 데이터가 담김
디스크에서 파일의 데이터를 가상 주소 공간에 매핑하는 기술
"Memory Mapped Files"에서 "memory"는 가상 주소 공간(Virtual Address Space)을 의미합니다. Memory Mapped Files는 파일을 가상 주소 공간에 매핑하는 기술입니다. 파일의 데이터가 실제로 물리 메모리에 로드되는 것은 아닙니다.
일반적으로 운영 체제는 파일을 물리 디스크에 저장합니다. 하지만 Memory Mapped Files를 사용하면 파일의 내용을 가상 주소 공간에 매핑하여 마치 메모리에 로드된 것처럼 접근할 수 있습니다. 파일의 데이터는 실제로 메모리에 로드되는 것이 아니라, 필요한 경우 페이지 폴트가 발생하여 필요한 페이지만 물리 메모리로 로드됩니다.
이러한 메모리 매핑은 읽기 및 쓰기 작업을 통해 파일의 데이터에 접근할 수 있는 이점을 제공합니다. 파일을 메모리에 매핑함으로써, 일반적인 메모리 접근 방식으로 파일을 조작하고 수정할 수 있습니다
🙄 매핑을 해야하는 이유?
파일과 메모리를 매핑하면 파일을 메모리처럼 접근할 수 있게 되어서 파일의 입출력의 효율성을 향상할 수 있다. 이렇게 파일과 매핑된 메모리 영역은 가상주소 공간에서 접근 가능하며, 해당 영역에 대한 읽기/쓰기 작업이 가능해진다. 쓰기 작업으로 인해 파일의 내용이 변경되면 매핑이 해제될때 디스크의 실제 파일에 해당 변경 사항이 반영된다.
⚡매핑이 이루어질 수 없는 경우?(mmap 함수를 짤 때 고려해야 함)
mmap
and munmap
System Call메모리 매핑 영역에서 페이지를 느리게 로드하고 메모리 매핑된 파일 자체를 매핑을 위한 백업 저장소로 사용함
비유
일반적인 메모리 할당 및 헤제 작업에서는 malloc을 이용해서 메모리를 할당하고 free를 이용해서 메모리를 해제했지만, mmap과 munmap은 파일 매핑된 메모리를 해제하는 특정한 상황해서 사용되는 함수이다.
void *mmap (void *addr, size_t length, int writable, int fd, off_t offset);
: 파일 디스크럽터(fd)로 열린 파일을 오프셋(offset)부터 시작해서 길이(length) 만큼의 바이트를 프로세스의 가상주소 공간에 주어진 주소(addr)부터 매핑한다.
addr에 주어진 length 만큼의 공간에 fd에 대응되는 파일의 offset에 해당하는 내용을 매핑한다. 이 때, 매핑된 해당 페이지의 쓰기 권한은 writable을 따른다. 주어진 addr은 반드시 page-aligned 되어 있어야 하며, 만약 매핑된 길이가 PGSIZE의 배수가 아닐 경우, 해당 부분은 0으로 채운뒤, 파일에 내용을 다시 쓸 때 날려버린다. VM_ANON과 마찬가지로, VM_FILE도 lazy loading 되어야 하며, VM_UNINIT을 활용해 spt에 넣어놓은 뒤에 fault가 났을 때 할당하는 방식으로 진행해야 한다.
void munmap (void *addr);
→ 파일을 닫거나 제거해도 매핑은 해제되지 않는다. 따라서 생성된 매핑은 munmap이 호출되거나 프로세스가 종료될 때까지 유효하다.
vm_file_init(void)
: 파일 백업 페이지 하위 시스템을 초기화한다.
file_backed_initializer
: page->operations에서 파일 백업 페이지에 대한 핸들러를 설정한다.
file_backed_destory
: 관련 파일을 닫아 파일 백업 페이지를 삭제한다.
파일 매핑 과정에서 읽기/쓰기 작업을 수행할 때 사용됨
읽기 및 쓰기 작업을 할 때 dirty bit도 사용될 수 있습니다. Dirty bit는 페이지가 수정되었는지 여부를 나타내는 플래그로 사용됩니다.
Memory Mapped Files를 사용할 때, 파일의 데이터는 가상 주소 공간에 매핑되어 있습니다. 읽기 작업을 수행할 때는 페이지 폴트가 발생하여 필요한 페이지를 물리 메모리로 로드하게 됩니다. 이때, 해당 페이지가 수정되지 않았다면 (dirty bit가 0인 경우), 디스크에서 페이지를 가져와서 메모리에 로드하면 됩니다.
그러나 쓰기 작업을 수행할 때는 다르게 동작합니다. 페이지가 수정되었을 경우 (dirty bit가 1인 경우), 해당 페이지의 내용을 디스크로 쓰기 위해 동기화 작업이 필요합니다. 일반적으로 운영 체제는 수정된 페이지를 디스크로 플러시하고, dirty bit를 0으로 설정하여 변경 사항이 반영되었음을 표시합니다.
따라서 Memory Mapped Files를 사용하면서 파일의 데이터를 수정하는 경우, dirty bit를 적절하게 관리하여 변경 사항을 추적하고 디스크에 동기화할 수 있습니다.
물리적 메모리 사용량을 최대화하기 위한 메모리 회수 기술
메모리 스왑은 물리적 메모리의 사용을 최대화하기 위한 메모리 회수 기술입니다. 메인 메모리의 프레임이 할당되면 시스템은 더 이상의 메모리 할당 요청을 처리할 수 없습니다. 이러한 경우, 현재 사용되지 않는 메모리 프레임을 디스크로 스왑아웃하여 메모리 자원을 해제하고 다른 응용 프로그램에 활용할 수 있게 됩니다.
주로 swap은 운영체제에서 수행된다. 시스템이 메모리가 부족하다는 것을 감지하고 메모리 할당 요청을 받으면 디스크 스왑을 위해 evict page를 선택한다. 그 후 해당 메모리 프레임의 정확한 상태가 디스크로 복사된다. 스왑아웃된 페이지에 접근하려는 프로세스가 있을 경우, 운영체제는 정확한 내용을 메모리로 다시 가져와서 해당 페이지를 복구한다.
스왑아웃 대상으로 선택되는 페이지는 익명 페이지(anonymous page) 또는 파일 지원 페이지(file-backed page)일 수 있습니다. 이 섹션에서는 각각의 경우를 다룰 것입니다.
void vm_anon_init (void);
스왑 디스크를 설정한다.
bool anon_initializer (struct page *page, enum vm_type type, void *kva);
스와핑을 지원하려면 익명 페이지에 몇가지 정보를 추가한다.
static bool anon_swap_in (struct page *page, void *kva);
디스크에서 메모리로 데이터 내용을 읽어 스왑 디스크에서 익명페이지로 스왑한다.
데이터의 위치는 페이지가 교체될 때 스왑 디스크에 저장되어 있어야 하는 페이지 구조체입니다. 스왑 테이블을 업데이트하는 것을 잊지 마세요(스왑 테이블 관리 참조).
static bool anon_swap_out (struct page *page);
메모리에서 디스크로 내용을 복사하여 익명 페이지를 스왑 디스크로 교체한다.
먼저 스왑 테이블을 사용하여 디스크에서 사용 가능한 스왑 슬롯을 찾은 다음 데이터 페이지를 해당 슬롯에 복사합니다. 데이터의 위치는 페이지 구조에 저장되어야 합니다. 디스크에 더 이상 여유 슬롯이 없으면 커널을 패닉시킬 수 있습니다.
파일 백업 페이지의 콘텐츠는 파일에서 가져오기 때문에 매핑된 파일을 백업 저장소로 사용한다.
파일 백업 페이지를 내보내면 매핑된 파일에 다시 기록한다.
static bool file_backed_swap_in (struct page *page, void *kva);
: 파일에서 내용을 읽어와서 kva에서 페이지를 교체한다. 파일 시스템과 동기화한다.
🤔kva는 뭘까?
여기서 kva는 "Kernel Virtual Address"의 약어입니다. 커널 가상 주소(Kernel Virtual Address)는 커널이 직접 접근할 수 있는 가상 주소를 의미합니다. 페이지를 스왑인할 때, 파일에서 내용을 읽어와서 kva에 해당하는 가상 주소에 적재합니다. 이를 위해서는 파일 시스템과 동기화 작업을 수행해야 합니다.
static bool file_backed_swap_out (struct page *page);
: 파일에 내용을 다시 써서 페이지를 바꾼다.
페이지를 스왑아웃하기 위해 해당 내용을 파일로 다시 기록합니다. 먼저 페이지가 dirty한지 확인하는 것이 좋습니다. 만약 dirty하지 않다면, 파일의 내용을 수정할 필요가 없습니다. 페이지를 스왑아웃한 후에는 페이지의 dirty 비트를 해제해야 합니다. 이를 위해 해당 페이지의 dirty 비트를 끄는 작업을 수행해야 합니다.
페이지를 프레임으로 변환할 때 사용