
프로그램을 컴파일하면 주소가 0번지부터 시작합니다. 그런데 실제 메모리에는 다른 프로그램들도 올라가 있으므로 0번지에 놓일 리가 없습니다. 주소가 두 종류라는 뜻입니다.
CPU가 내보내는 주소는 항상 논리 주소입니다. 따라서 메모리에 닿기 전에 누군가 물리 주소로 바꿔 줘야 합니다.
논리 주소를 물리 주소로 결정하는 일을 주소 바인딩(address binding)이라고 합니다. 언제 결정하느냐에 따라 셋으로 나뉩니다.
| 방식 | 결정 시점 | 생성되는 코드 | 실행 중 이동 |
|---|---|---|---|
| compile time binding | 컴파일할 때 | 절대 코드 (absolute code) | 불가능 |
| load time binding | 메모리에 올릴 때 (loader가 결정) | 재배치 가능 코드 (relocatable code) | 불가능 |
| execution time binding | 실행 중에 매 접근마다 | 재배치 가능 코드 | 가능 |
compile time binding은 물리 주소가 컴파일 시점에 박히므로, 그 자리가 비어 있지 않으면 실행할 수 없습니다. 지금 쓰는 시스템은 모두 execution time binding입니다. 실행 도중에도 프로세스를 다른 위치로 옮길 수 있어야 하기 때문인데, 매 주소 접근마다 변환이 필요하므로 하드웨어 지원이 필수입니다.
그 하드웨어가 MMU(Memory Management Unit)입니다. 레지스터 두 개를 씁니다.
변환 규칙은 "논리 주소에 시작 주소를 더한다"입니다. 여기에 더해, 남의 영역을 침범하지 않는지 limit register로 검사합니다.
relocation register가 14000, limit register가 3000입니다.

mode bit이 권한을 막았다면, limit register는 영역을 막습니다. 둘 다 소프트웨어가 아니라 하드웨어가 검사한다는 점이 같습니다.
메모리는 늘 부족하므로 "안 쓰는 것은 안 올린다"는 아이디어가 여러 형태로 나옵니다.
| 기법 | 내용 | 비고 |
|---|---|---|
| dynamic loading | 해당 루틴이 호출될 때 메모리에 올림 | 오류 처리처럼 자주 안 쓰는 코드에 효과적 |
| static linking | 라이브러리를 실행 파일에 포함시켜 둠 | 파일이 커지고, 같은 라이브러리가 프로세스마다 중복 |
| dynamic linking | 실행 시점에 라이브러리를 연결 | 메모리에 한 벌만 두고 여러 프로세스가 공유 |
| overlays | 필요한 부분만 올리되 프로그래머가 직접 관리 | 메모리가 극히 작던 시절의 수작업 방식 |
| swapping | 프로세스를 통째로 디스크 swap area로 내보냄 | 내보내기가 swap out, 다시 올리기가 swap in |
swapping에서는 주소 바인딩 방식이 바로 문제가 됩니다. compile time이나 load time binding이면 swap in할 때 원래 있던 자리로만 돌아갈 수 있습니다. execution time binding이면 아무 빈 자리에나 올리면 됩니다.
메모리는 크게 운영체제 상주 영역과 사용자 프로세스 영역으로 나뉩니다. 사용자 영역을 어떻게 나눠 주느냐에서 갈립니다.
연속 할당은 다시 둘로 나뉩니다.
| 구분 | 고정분할 (fixed partition) | 가변분할 (variable partition) |
|---|---|---|
| 방식 | 미리 정해진 크기로 영역을 나눠 둠 | 프로세스 크기에 맞춰 그때그때 할당 |
| 동시 적재 프로세스 수 | 분할 개수로 고정 | 유동적 |
| 발생하는 조각 | 외부 조각 + 내부 조각 | 외부 조각 |
조각(fragmentation)은 쓸 수 있는데 쓰이지 못하는 메모리입니다. 생기는 자리가 다릅니다.
고정분할은 정해진 칸에 넣으므로 내부 조각이 생기고, 가변분할은 딱 맞게 주므로 내부 조각은 없지만 프로세스가 빠져나간 자리에 외부 조각이 생깁니다.
가변분할에서 비어 있는 공간을 hole이라고 합니다. 크기가 제각각인 여러 hole 중 어디에 넣을지 고르는 문제를 dynamic storage allocation problem이라고 하며, 전략이 셋입니다.
| 전략 | 동작 | 장점 | 단점 |
|---|---|---|---|
| first fit | 처음 만나는 충분한 hole에 배치 | 탐색이 빨라 가장 빠름 | 배치 품질을 따지지 않음 |
| best fit | 들어가는 것 중 가장 작은 hole에 배치 | 큰 hole을 보존 | 전체 탐색 필요, 쓸모없이 작은 조각이 많이 남음 |
| worst fit | 가장 큰 hole에 배치 | 남는 조각이 커서 재사용 가능 | 전체 탐색 필요, 큰 hole이 빨리 사라짐 |
어느 전략을 써도 외부 조각은 남습니다. 흩어진 조각을 한쪽으로 몰아 하나의 큰 공간으로 만드는 작업이 compaction인데, 실행 중인 프로세스를 옮기는 일이라 비용이 매우 크고 execution time binding일 때만 가능합니다.
결국 연속 할당으로는 한계가 있습니다. 프로세스를 잘게 나눠 흩어진 자리에 올리면 외부 조각 문제가 사라지는데, 이것이 paging과 segmentation입니다.