이번에는 Anonymous Memory가 아닌 File-Backed memory, 다시 말해 Memory Mapped Page에 대해 구현해보도록 한다.
File backed page에 있는 내용물들은 모두 디스크에서 존재하고 있는 파일을 복사한 것이다. 만약 페이지 폴트가 일어나면 바로 물리 프레임이 할당되고 물리 프레임에 파일의 데이터가 복사된다. 이 때 디스크 I/O를 통해 데이터를 복사하는 것이 아닌, DMA 방식으로 디스크에서 파일을 바로 읽어와서 복사한다.
이 때 디스크에 있는 파일에 대한 유저 가상 페이지를 미리 가상 주소 공간에 할당해주는 것을 mmap이라 하고, 페이지와 물리 메모리가 연결된 경우 그 연결을 끊어주는 것을 munmap이라 한다.
만약 file backed page가 memory unmapped되거나 swap out 되면, 해당 메모리에 변화가 생긴 경우(dirty bit) 그 변화를 파일에 업데이트하고 memory unmapped되거나 swap out되어야 한다.
mmap() 시스템 콜에 의해 매핑된 가상 메모리는 스택과 힙 사이의 미할당 공간(스택도 아니고 힙도 아닌)에 매핑된다.
일단 힙은 크게 두 가지 시스템 콜에 의해 구현되는데, segment의 크기를 linear하게 늘리는 **sbrk(segment의 끝을 늘린다)**와 mmap 중 하나를 택해 커널로부터 메모리를 할당받아 사용하는 경우가 많다.
일단 mmap으로 할당받을 수 있는 페이지는 스택과 힙 사이의 빈 공간을 할당받지만, heap allocator 안에서 구현될 경우에는 heap에 페이지를 할당하도록 구현된다.
brk
sbrk() 혹은 brk()의 경우에는 전통적으로 UNIX에서 메모리를 할당하는 방식이다. 인자로 들어가는 크기만큼 segment의 크기를 늘려준다.
mmap
mmap()의 경우에는 brk처럼 굳이 한 세그먼트의 끝에서부터 늘리는 것이 아니라, 독립된 공간에도 메모리를 할당해줄 수 있다. mmap은 파일의 메모리를 페이지에 매핑하는 데도 사용할 수 있지만, ANON 페이지와 같이 그냥 file-backed memory가 아닌 페이지의 경우에도 매핑해 줄 수 있다.
요즘에는 대부분의 Heap Allocator들은 sbrk보다는 mmap syscall을 통해서 메모리를 확보한다.
리눅스의 경우
mmap_threshold
보다 큰 크기의) 요청에 대해서 mmap 수행 (참고)