06. vm-api
- Haram Lee
- 2026-04-14
- studies / 26-1 / operating-systems
Virtual Memory
- Virtual memory는 일종의 level of indirection이다.
- 프로그램은 physical address를 직접 쓰는 대신 virtual address를 사용하고, 실행 중에 address translation mechanism이 이를 physical address로 바꾼다.
- physical memory를 프로세스에 직접 노출하면 unsafe하다. 여러 프로세스를 메모리에 함께 올려 두면, 잘못된 memory access가 다른 프로세스나 OS를 망가뜨릴 수 있기 때문이다.
- 그래서 OS는 virtual address라는 새로운 추상화를 만들고, 이를 통해 Safety, Convenience, Efficiency를 얻고자 한다.
Goals
- Protection
- 다른 프로세스와 OS를 보호해야 한다.
- 한 프로세스가 실패해도 다른 프로세스에 영향을 주지 않도록 isolation을 제공해야 한다.
- cooperating processes라면 일부 메모리를 공유할 수도 있어야 한다.
- Transparency
- 프로세스는 메모리가 실제로 공유되고 있다는 사실을 몰라도 된다.
- 프로그래머에게는 크고 연속적인 메모리 공간처럼 보여야 한다.
- Efficiency
- variable-sized request 때문에 생기는 fragmentation을 줄여야 한다.
- address translation은 자주 일어나므로 시간 오버헤드를 줄이기 위해 하드웨어 지원도 필요하다.
(Virtual) Address Space
- 각 프로세스는 자기만의 virtual address space를 가진다.
- 이것은 프로세스가 보는 추상적인 메모리 모습이다.
- 주소 공간에는 그 프로세스의 모든 memory state가 들어 있다.
- 크게 보면 다음과 같이 나뉜다.
- Static area
exec()시점에 잡힌다.- code와 data가 여기에 들어간다.
- Dynamic area
- runtime에 할당된다.
- heap과 stack이 여기에 들어가며, 커지거나 줄어들 수 있다.
- Static area
- 슬라이드 그림에서는 아래쪽에 read-only segment인
.init,.text,.rodata가 있고, 그 위에 read/write segment인.data,.bss가 있다. - heap은 위로 자라고, 그 끝 위치를
brk가 나타낸다. - stack은 반대편에서 생성되고 자라난다.
- kernel virtual memory는 user code에서 접근할 수 없다.
- 각 프로세스는 large하고 contiguous한 private address space를 가진 것처럼 보인다.
- 실제 translation은 run time에 일어난다.
- 또한 virtual memory는 lazy allocation을 지원하므로, 프로그램 전체 주소 공간이 한꺼번에 physical memory에 올라가 있을 필요는 없다.
Virtual Memory APIs
- 프로그래머가 직접 만지는 메모리 API는 크게 두 층으로 볼 수 있다.
- libc 쪽 API
malloc()free()calloc()realloc()
- OS system call 쪽 API
brk()sbrk()mmap()
- libc 쪽 API
malloc/free는 heap을 관리하는 데 쓰이고, heap 자체 크기를 바꾸는 일은 내부적으로brk/sbrk가 맡는다.- 즉, 프로그래머는 보통
malloc()을 쓰지만, 그 아래에서는 libc와 OS가 함께 주소 공간을 관리한다.
malloc() / free()
malloc()은 heap에 memory region을 할당한다.- 인자
size_t size- 할당할 메모리 크기(byte 단위)
- 반환값
- 성공하면 할당된 block의 시작 주소를 가리키는 포인터
- 실패하면
NULL
- 인자
free()는malloc()으로 할당한 memory region을 해제한다.- 인자
void *ptr- 해제할 memory block의 포인터
- 반환값은 없다.
- 인자
c
#include <stdlib.h>
void* malloc(size_t size);
void free(void* ptr);- 슬라이드 예시에서는 지역 변수 포인터
pi가 stack에 있고, 실제로 할당된int4개짜리 공간은 heap에 생긴다. - 즉
pi자체는 stack에 있지만,malloc(sizeof(int) * 4)가 만든 배열 공간은 heap에 있다. - 이후
free(pi)를 호출하면 그 heap block이 해제된다.
c
int *pi; // local variable
pi = malloc(sizeof(int) * 4);
free(pi);calloc() / realloc()
calloc()은 memory를 할당하면서 0으로 초기화한다.- 인자
size_t num- 객체 개수
size_t size- 각 객체 크기(byte)
- 인자
realloc()은 기존 memory block의 크기를 바꾼다.- 인자
void *ptr- 기존 block 포인터
size_t size- 새 크기
- 실패하면 원래 포인터를 그대로 반환한다.
- 인자
c
#include <stdlib.h>
void *calloc(size_t num, size_t size);
void *realloc(void *ptr, size_t size);brk() / sbrk()
- heap 공간이 부족하면 libc의 allocator가 OS에게 heap을 더 크게 만들어 달라고 요청해야 한다.
- 여기서 break는 주소 공간에서 heap의 끝 위치를 뜻한다.
malloc()은 내부적으로brk()나sbrk()를 사용해 program break를 확장할 수 있다.sbrk()는brk()와 비슷하다.- 슬라이드는 프로그래머가 직접
brk()나sbrk()를 호출하지 말라고 강조한다. 보통은malloc()이 내부적으로 사용한다.
c
#include <unistd.h>
int brk(void *addr);
void *sbrk(intptr_t increment);mmap()
mmap()은 호출한 프로세스의 virtual address space에 새로운 mapping을 만든다.- 주요 인자는 다음과 같다.
addr- 새로운 mapping의 시작 주소
- page boundary에 맞게 정렬되어야 한다
NULL이면 커널이 적절한 주소를 골라 준다NULL이 아니면 커널에게 “여기쯤 배치해 줘”라는 hint를 주는 의미다
length- mapping 길이
prot- protection 정보
PROT_EXEC,PROT_READ,PROT_WRITE,PROT_NONE
flags- mapping 속성
MAP_PRIVATE,MAP_SHARED,MAP_ANONYMOUS등
fd,offset- file mapping에 사용할 file descriptor와 file offset
- 즉
mmap()은 “주소 공간의 어떤 구간을 무언가와 연결하는 함수”라고 볼 수 있다.
c
#include <sys/mman.h>
void *mmap(void *ptr, size_t length, int prot, int flags,
int fd, off_t offset);Uniformity of Memory Mapping
- 가상 메모리의 중요한 장점 중 하나는, 여러 종류의 backing store를 통일된 방식으로 다룰 수 있다는 점이다.
- 동적으로 할당된 virtual memory area는 다음을 backing store로 가질 수 있다.
- file
- device memory
- shared memory
- none
- 즉 anonymous mapping
- 결국 프로세스 입장에서는 이 모든 것이 주소 공간 안에 매핑된 memory region으로 보인다.
File Mapping vs. Anonymous Mapping
- File mapping
- backing store가 regular file이다.
- memory region을 file region에 대응시킨다.
- 그래서 파일 내용을
read()/write()대신 load/store instruction으로 다룰 수 있다.
- Anonymous mapping
- file로 backing되지 않는 virtual address space다.
- memory region을 0으로 채워진 memory area에 매핑한다.
- 흔히 zero-page mapping처럼 생각하면 된다.
Shared Mapping vs. Private Mapping
- 여러 프로세스가 같은 backing store를 자기 virtual address space에 매핑할 수 있다.
- 이때 두 가지 방식이 있다.
- Shared mapping
- shared page에 대한 수정이 모든 관련 프로세스에게 보인다.
- Private mapping
- 수정 내용이 다른 프로세스에게 보이지 않는다.
- 내부적으로 copy-on-write와 연결된다.
- Shared mapping
- 슬라이드는 이걸 네 가지 경우로 정리한다.
- Private file mapping
- Private anonymous mapping
- Shared file mapping
- Shared anonymous mapping
- 즉 file이냐 anonymous냐, shared냐 private냐는 서로 독립적인 축이다.