CPU(Central Processing Unit)가 접근할 수 있는 '저장장치'는 CPU Register, 그리고 Main Memory 뿐이다.
#Memory Hierarchy
CPU는 Main Memory에서 프로세스들을 실행하기 위한 명령어/데이터를 가져와서 수행한다.
프로세스들은 Main Memory 에 독립된 공간을 할당받는다.
여러 프로세스들이 공유하게 될 이 Main Memory라는 공간을 운영체제가 어떻게 관리하는지 알아보는 게 이 글의 목적이다.
#1 Main Memory 주소 할당과정
#1-1 '독립된 공간'의 구분
'독립된 공간'을 할당받으려면, 그 구분이 확실해야 될 것이다.
그래서 존재하는것들이 바로
- Base Register
: smallest legal physical address, 즉, 프로세스의 메모리 영역이 시작되는 주소 값을 저장하는 레지스터 - Limit Register
: size of the range, 즉, 프로세스의 메모리 영역의 '크기의 값'을 저장하는 레지스터 (주소값 아님! 메모리 영역이 끝나는 주소 값은 base 레지스터의 값 + limit 레지스터의 값 이 되겠다)
>> 오직 운영체제만이 이 값들에 접근해서 바꿀 수 있다. User Program에서는 불가능. Previleged Instruction이 수행되어야 하는데, 이는 Kernel Level에서만 수행되기 때문.
#User Level and Kernel Level
그런데 그 공간 밖의 주소에 접근을 하려고 한다면? 당연히 안되겠지.
그래서 위에 언급한 두 레지스터의 값들을 이용해 'legitimate memory access'인지 확인을 하고, 만약 범위 밖의 접근 (illegitimate memory access)이라면 trap (interrupt의 한 종류)을 발생시킨다.
#Interrupt
#1-2 '독립된 공간', 즉 주소의 할당 Address binding
다시 말해 명령어와 데이터가 메모리 주소에 로드되는 것.
'Binding'은 수행되는 시점에 따라 세 가지로 구분된다.
- Compile Time Binding
: Compile 시점에 프로세스에게 할당될 메모리의 위치를 알고 있는 경우, 컴파일러는 특정 위치에서 위치가 바뀌지 않는 'absolute code'를 생성할 수 있다. 만약 메모리 주소의 시작점이 바뀐다면, 다시 컴파일되어야 한다. - Load Time Binding
: Compile 시점에 프로세스에게 할당될 메모리의 위치를 알고 있지 않은 경우, binding은 load time까지 대기한다. - Execution Time Binding
: 프로세스가 실행되는 중에 다른 Memory Segment로 이동이 가능한 경우, binding은 runtime까지 대기한다.
컴파일러에 대해 어느정도 이해가 있어야 받아들이기 쉬운 개념인 것 같다.
'주소의 binding 을 어떻게 효율적으로 해 줄 것인가?'가 운영체제가 답해야 하는 문제의 요지이다.
#1-3 Logical Address Space 와 Physical Address Space
Logical Address: Virtual Address(가상 주소) 라고 하기도 하며, CPU가 생성한다. User Program은 항상 이 친구만 다룬다.
Physical Address: Memory Unit 관점에서의 주소, 실질 주소. User Program은 이친구를 만나지 못한다.
- Compile Time Binding
: Logical Address == Physical Address - Load Time Binding
: Logical Address == Physical Address - Execution Time Binding
: Logical Address != Physical Address
- Memory -Management Unit, MMU
: 가상 주소를 실질 주소로 변환, 즉, 'mapping' 시켜주는 하드웨어.
간단한 scheme의 예시로, 위에서 언급한 Base register를 Relocation register로 활용하여 실질 주소를 바인딩한다.
다시 말해, relocation register에 저장된 시작점을 offset으로 전부 더해주는 방법으로 relocation을 한 것.
>> Logical Address 가 [0, Max]였다면
Physical Address는 [Relocation offset +0, Relocation offset + Max]인 것이다.
#2 Linking, Loading
프로그램들은 Linking, 그리고 Loading의 과정을 거쳐 메모리에 올라간다.
- Linking
: loadable image 생성과정.
- Dynamic Linking
: execution time에 linking이 수행된다 (주로 라이브러리에 사용). 구체적으로, 특정 라이브러리를 어떻게 찾을 것인지 알려주는 'stub'이라는 코드가 메모리에 존재하는지 여부를 execution time에 확인하고, 존재하지 않는 경우에만 디스크에서 stub을 가져온다.
- Dynamic Linking
- Loading
: loadable image를 메모리에 복사하는 과정. 이미 load가 되어있는 프로그램들과 비교하고, 주소를 업데이트한다
- Dynamic Loading
: 루틴(프로그램의 흐름이라고 생각하면 된다. 어떤 코드가 어떤 코드를 호출하고, 등등)이 relocatable load format으로, 즉 포장되어 언제든지 메모리에 로드 될 수 있는 상태로 대기한다. 그리고 execution time 에 호출됐을 시에만 메모리에 로드된다.
- Dynamic Loading
Linking과 Loading을 Dynamic한 방법으로 수행하면 메모리에 필요한 데이터와 코드만 로드되어 효율이 좋아지는구나 라는 것을 직관적으로 생각 할 수 있다. 식자재를 한꺼번에 도마 위에 다 올려놓고 쓰는게 아니라, 손질해놓고 냉장고에서 필요할 때만 꺼내 쓰는 것과 같은 상황이다.
'프로그램이 갖는 코드와 데이터를 메모리에 로드하는 과정을 어떻게 효율적으로 수행할 것인가?'
말은 조금 다르지만 어쨌든 처음부터 계속 반복되고 있는 질문이다.
*오개념 지적 대환영*
#키워드 : (게시글이 있는 경우) 링크를 참고하시거나, 검색하면서 읽어주세요.이해에 꼭 필요한 개념입니다.
해당 게시글은 Operating Systems: Three Easy Pieces(#혜성책), Operating System Concepts (#공룡책), 그리고 이 도서를 기반으로 한 학부 수업 자료를 참고하여 작성하였습니다.
'CS > Operating Systems' 카테고리의 다른 글
| OS_Contiguous Allocation(Fragmentation) (0) | 2020.12.06 |
|---|---|
| OS_Deadlock(3): Solution(Prevention and Avoidance -Banker's Algorithm) (0) | 2020.11.30 |
| OS_Deadlock(2): Solution(Detection and Recovery) (0) | 2020.11.30 |
| OS_Deadlock(1): Problem (0) | 2020.11.29 |
| OS_Swapping (0) | 2020.11.28 |