CPU가 접근 가능한 저장소는 CPU 내부의 Register
그리고 Main memory
이다.
CPU는 여기에서 command
를 load
하여 processing
한다.
보통 CPU는 register
에 1 clock cycle
내에 접근이 가능하다.
하지만 만약 command
가 Main memory
에 있을 경우 1 clock
이상의 시간이 소요되어 stall(지연)
된다. 이러면 낭비가 심해지기 때문에 CPU
와 Main memory
사이에 Cache
를 두어 문제를 해결한다.
Program은 Binary execution file
형태로 디스크에 저장되어 있으며 실행되기 위해서는 Main memory
로 올라와서 Process
가 되어야 한다.
Process는 효율적인 실행을 위해 디스크와 Main memory 사이를 왔다갔다 하는데 이 때 Main memory에 올라오기 위해 대기하고 있는 Process들의 집합
을 Input Queue
라 부른다.
코드에서 사용하는 symbol 형태
(ex. pointer, *a)는 Compiler
에 의해 Relocatable address(재배치 가능 주소)
로 binding
되고 이는 linkage editor
또는 loader
에 의해 Absolute address(절대 주소, 물리 주소)
로 binding
된다.
Binding
은 시점에 따라 세 가지로 나눌 수 있다.
- Compile time binding
- Compile time에 Memory 내의 위치를 직접 알 수 있으면(process가 R번지부터 시작한다는 사실) Compiler는
Absolute code(절대 코드)
를 생성할 수 있다. 하지만 이 위치가 변경되어야 한다면 이 코드는 다시 compile되어야 한다.
- Compile time에 Memory 내의 위치를 직접 알 수 있으면(process가 R번지부터 시작한다는 사실) Compiler는
- Load time binding
- Compile time에 적재 장소를 알 수 없다면
Compiler
는Binary code
를Relocatable code
로 만들어야 한다.Relocatable code
는 시작 주소가 변경되더라도 사용자 코드를 다시 reload만 하면 된다.
- Compile time에 적재 장소를 알 수 없다면
- Excution binding
- Process가 실행되는 중간에 memory 내의 한 segment에서 다른 segment로 옮겨질 수 있을 때 “바인딩이 실행 시간까지 허용되었다” 라고 이야기 하며, 이것이 가능하려면 특별한 Hardware를 이용해야 한다.
CPU가 생성하는 주소를 Logical address(논리 주소)
라 하며, Memory가 다루는 주소를 Physical address(물리 주소)
라 한다.
Compile time binding
, Load time binding
에서는 Logical address
와 Physical address
가 같지만 Excution binding
에서는 서로 다르다. 이 때 사용하는 Logical address를 Virtual address
라고 부른다.
Virtual address
프로그램 실행 중 Physical address
로 바뀌어야 하는데 이 바꾸는 작업을 Mapping
이라 하며 MMU (Memory Management Unit)
에서 작업이 이루어진다.
Dynamic Loading(동적 적재)
Physical memory 크기의 제한때문에 큰 program의 경우 미리 memory에 모두 올라와있지 못한다. 이를 해결하지 위해 Dynamic Loading
이 사용된다.
각 routine은 실제 호출되기 전까지는 memory에 올라오지 않고 relocatable 상태로 disk에 대기하고 있다가 Main program이 memory에 올라와 실행되고 이 routine이 다른 routine을 호출하게 되면 호출된 routine이 이미 memory에 laoding되어 있는지 확인한다. 없으면 Relocatable linking loader
가 호출되어 요구된 routine을 memory로 가져오고 이러한 변화를 테이블에 기록해 둔다. 그 후 CPU 제어는 중단되었던 routine으로 보내진다.
Swapping
Process가 실행되기 위해서는 memory에 있어야 하지만 항상 점유하고 있을 수는 없다. 따라서 실행되는 도중에 임시로 Sub memory로 보내졌다가 다시 Main memory로 돌아올 수 있다.
Swapping을 변형하여 우선순위를 두어 처리하는 것을 Roll-in, Roll-out
이라고도 부른다.
Swapping system은 Context-switching time이 상당히 오래 걸린다.
Fragmentation
memory의 이곳 저곳을 점유하다보면 크기에 따라 중간중간 비는 공간이 나타나게 되고 이를 Fragmentation
이라 부른다.
Fragmentation
문제를 해결하기 위해 두 가지 기법을 사용할 수 있다.
- Paging
- Segmentation
Paging
Physical memory는 frame
이라는 같은 크기의 block들로 나누어져 있고 Logical memory는 page
라는 같은 크기의 block들로 나누어져 있다.
CPU에서 나오는 모든 주소는 Page number(p)
와 Offset(d)
로 구성된다. Page number
는 Page table
에 access할 때 사용되며 Page table
은 Main memory에서 각 page가 점유하는 주소를 가지고 있다. 이 주소에 Offset
을 더하면 원하는 Physical address
가 된다.
{:class=”img-responsive”}
Frame 및 Page의 크기는 Hardware에 의해 정의되며 Page의 크기는 일반적으로 512 byte ~ 16 MB 사이이며 2의 제곱으로 증가한다.
Logical address의 크기가 2^m 이고 page가 2^n의 크기를 갖는다면 Logical address의 상위 m-n 비트는 page number를 나타내고, 하위 n 비트는 page offset을 나타낸다.
{:class=”img-responsive”}
Segmentation
사용자는 하나의 Program을 subroutine
, procedure
, function 또는 module
들을 가지고 있는 것으로 생각하고, Table
, Array
, Stack
등의 다양한 변수를 사용한다.
이러한 사용자가 바라보는 Memory의 관점을 그대로 지원하는 Memory Management 기법이다.
쉬운 구현을 위해 Segment name 대신 Segment number가 System에 의해 매겨지고 Segment는 number로 불리운다. 때문에 Logical address는 <segment-number, offset>
으로 구성된다.
{:class=”img-responsive”}
Virtual Memory
Process 전체가 Memory에 올라오지 않더라도 실행이 가능하게 하는 기법이다. Physical memory로부터 사용자 관점의 Logical memory를 분리시켜 Main memory를 균일한 크기의 저장 공간으로 구성된 엄청나게 큰 배열로 추상화시켜 준다.
- 장점
- (Physical) Memory size의 제약으로부터 자유로워진다.
- File의 공유를 쉽게 해주고 Shared memory 구현을 가능케 한다.
- Process 생성을 효율적으로 처리할 수 있는 Mechanism을 제공한다.
- 많은 program을 동시에 수행 가능하고 이에 따라 응답 시간(response time, turnaround time)은 늘어나지 않으면서도 CPU 이용률(utilization)과 처리율(throughput)이 높아진다.
- swap하는데 필요한 입/출력 횟수가 줄어들어 program들이 상대적으로 빠르게 실행된다.
단점
- 구현하기 어렵다.
- 잘못 사용하면 성능이 크게 저하된다.
앞에서 본 Memory management 기법 중 Dynamic loading은 process 전체를 memory에 올려야 한다는 제약을 어느정도 막아주긴 하지만 프로그래머가 추가적인 작업을 해야한다.
앞서 본 것처럼
page frame
들로 인해 Physical memory는 연속적인 공간이 아닐 수 있다. MMU(Memory Management Unit)는 Physical memory를 Logical memory로 mapping한다.Virtual Memory
의 각area
는 다음과 같이 사용된다.Stack
- main() 함수, Callback 함수의 주소, 지역변수, 파라미터, return value가 저장되는 영역이다.
- Sparse
- 빈 공간을 포함한 Stack과 Heap 사이의 영역이다.
- Heap
- 동적 메모리 할당 영역이다.
- Data
- 전역변수, 정적변수(static), 배열, 구조체, 상수가 저장되는 영역이다.
- Data 영역은 두 가지 영역으로 구분할 수 있다.
- Data
- 초기값이 있는 경우
- BSS (Block Started by Symbol)
- 초기값이 없는 경우우
- Data
- Code
- 작성한 Code가 저장되는 영역이다.
{:class=”img-responsive”}
- Code, Data, Stack 영역은 Compiler가 Memory의 크기를 결정한다.
- Heap 영역의 크기는 개발자에 의해 프로그램 동작 시 결정된다.
- Stack의 지역변수는 사용 후 소멸하므로 데이터 용량이 불확실하다. 따라서 밑에서부터 올라가면서 값이 채워진다.
- Heap overflow
- Heap 영역이 Stack 영역을 침범한 경우
- Stack overflow
- Stack 영역이 Heap 영역을 침범한 경우
아래 그림은 wikipedia에서 설명하고 있는 동적 할당에 대한 그림이다.
{:class=”img-responsive”}
출처
아래의 글들을 교재삼아 작성하였습니다.