메모리안에는 여러개의 프로그램이 동시에 들어가서 실행한다.
메모리를 나눠서 여러 프로세스가 동시에 들어갈 수 있게 해야한다.
메모리는 크기가 한정적이고 실행을 동시에 하고싶어하는 프로세스의 개수는 많기 때문에 가급적이면 많은 프로세스들이 동시에 메모리에 들어갈 수 있도록 자른다.
어떻게 메모리를 효율적으로 할당하는지가 중요한 문제다.
메모리 관리에 있어서 3가지가 있다.
위 이미지는 프로세스 이미지이다.
위 모양 그대로 프로세스가 메모리 안으로 들어가야 한다. 그런데 명령이나 데이터의 주소를 알 수 없다. 메모리를 4개로 잘라서 프로그램을 집어넣고 실행한다. 그런데 프로그램은 1, 2, 3, 4 중 어디에 들어갈지 알 수 없다. 컴파일해서 기계어로 바꾸는 단계에서는 메모리의 몇 번지로 가는지 알 수 없기 때문에 다음 명령이 몇번지인지 알 수 있는 방법이 없다. 그래서 항상 컴파일할 때는 0번지 기준으로 컴파일한다.
그래서 시작주소가 1000번지라면 350번지라고 생각한 지점은 1350번지가 된다. 모든 주소에다가 1000씩 더해야 실제 주소가 나오게 된다.
위 과정을 Relocation
이라 한다.
즉, 우리의 프로그램이 메모리 상에 어떤 위치에 들어가느냐에 따라서 모든 프로그램 안에 있는 데이터와 명령어들의 주소가 바뀌어야 하는데, 주소를 바꿔주는 작업을 Relocation
이라 한다.
실제 메모리 상황에 맞게 주소 변경을 해줘야 한다.
우리의 프로그램이 실행될 때 1000~2000번지에 있을 때, 데이터 저장을 2500번지에 저장하면 안된다. 프로그램은 자신한테 할당된 이외의 영역에 접근해서는 안된다.
이를 Protection
이라 부른다.
하지만 가끔은 Sharing
을 한다. OS가 공유할 수 있게 허용한 공간이 존재한다.
External fragmentation
Compaction
주기적으로 실행EX) 16M 프로그램
Fixed Partitioning에서 파티션안에 프로그램이 들어가는데, 프로그램의 크기가 파티션보다 작으면 공간이 남는다. 이러한 공간을 Internal Fragmentation
이라 부른다.
Dynamic Partitioning에서는 프로그램과 프로그램 사이에 External Fragmentation
이 존재한다.
Internal Fragmentation
은 파티션 개수로 정해져 있다.
Buddy System은 Fixed + Dynamic Partitioning 이라고 볼 수 있다.
dynamic 처럼 공간인 필요할 때마다 할당해서 공간을 나눠준다. 그런데 적당한 크기의 공간은 프로세스가 요청한 크기가 아니라, 어떠한 규칙을 가지고 크기를 정한다.
각 방법(Fixed, Dynamic, Buddy)의 장단점을 잘 알고있어야 한다.
메모리 매니지먼트에서 중요한 것
x번 페이지 안에서 offset y
처럼 있기 때문에 연속된 주소 X아래의 Relocation, Protection 방식은 Fixed/Dynamic Partitioning, Buddy System에서 사용한다.
모든 번지에 1000씩을 더하는 방법은 컴파일을 다시하는 것이다. 이 것은 시간이 굉장히 많이 걸린다. 이 방법보다는 Base Register
를 사용한다. 프로그램의 시작 번지가 3000이면, Base Register에 3000을 집어넣는다.
JMP 300 ⇒ 300 주소에다가 Base Register값을 더한다 ⇒ JMP 3300
Relocation : Relative Address + Base Register ⇒ Physical Address
Base Register는 프로그램 영역의 시작점이다. 프로세스의 시작점인 PCB가 있는 영역이 아니라 프로그램 코드의 시작점이 들어있어야 한다.
Relocation 하는 부분은 Relative Address랑 Base Register값을 더해서 Physical Address가 되는 부분까지이다.
Protection을 하기 위해서 Bounds Register
를 사용한다.
Bounds Register 에 프로그램 영역(프로그램 코드와 데이터)의 마지막 주소값을 넣는다. 스택 영역은 프로세스가 관리하는 영역이다.
0번지 기준으로 컴파일 했을 때 프로그램의 마지막 주소가 1000번지이고 프로그램을 3000번지에 집어넣는다면, 마지막 주소값은 4000번지가 된다.
Base Register에는 3000을 넣어두고 Bounds Register에는 4000을 넣는다.
Base Register + Relative Address > Bounds Register ⇒ 인터럽트 발생
💡시스템안에 Base Register와 Bounds Register는 몇 쌍이 있어야 할까?
만약 시스템이 메모리안에 동시에 최대 10개의 프로그램이 들어갈 수 있다면, Base Register와 Bounds Register는 몇 개가 필요할까?
1개, 한 번에 한 프로그램만 실행되므로
메모리를 동일한 크기의 조각으로 전부 자른다. 이런 한 조각을 page frame
이라고 부른다.
그 다음 프로그램을 이 조각에 맞춰서 자른다. 이 조각을 page
라고 부른다. 마지막 페이지는 실제 프레임보다 작기 때문에 마지막 페이지에 한해서는 Internal Fragmentation
이 발생한다. 하지만 External Fragmentation
은 발생하지 않는다.
Dynamic Partitioning이었다면 D를 실행시킬 수 없다. 하지만 paging 시스템이기 때문에 연속되지 않은 5개의 프레임을 할당해서 프로그램을 실행할 수 있다.
페이지 테이블에는 각 프로세스의 각 페이지가 몇 번 프레임에 들어있는지를 나타낸다. 그리고 relocation하기 위해서 프로그램에서 사용하는 주소도 컴파일할 때 x번 페이지의 오프셋 y
형식으로 주소를 만들어서 컴파일한다.
page size = 1K = = 1024
Relocation
1502 ⇒ 1502/1024 번째 페이지, 1502 % 1024 offset ⇒ 2번째 페이지 478번지 offset
그래서 paging 시스템의 장점은 우리가 컴파일하는 방식을 바꾸지 않아도 된다.
Protection
오프셋은 10비트로 표현된다. 따라서 오프셋은 10비트보다 더 큰 수일 수 없다. 결국 오프셋은 페이지 안에 있는 어떤 주소를 나타낸다.
하지만 다른 사람의 페이지 프레임 번호에 접근하게 되면 문제가 된다. 이 부분은 페이지 테이블을 찾을 때 페이지 번호를 확인해서 해결한다. 자신에게 할당된 페이지 프레임에 접근해야 한다.
이렇게 paging 시스템을 사용하면 relocation과 protection을 동시에 할 수 있다.
real memory 시스템에서는 Segmentation 기법을 사용할 필요가 없다. 그러나 Virtual Memory 시스템이 되면 Segmentation 기법이 일부 도입되어야 한다. 왜냐하면 Virtual Memory 시스템에서는 전체 프로그램이 다 메모리에 들어가는 것이 아니라 일부만 메모리에 들어온다.
Dynamic Partitioning은 프로그램 전체가 들어갔다 나갔다해서 공백에 전체 프로그램이 들어가기엔 공백이 너무 작다. 하지만 Segmentation 기법에서는 Segment 하나가 들어왔다 나갔다 하기 때문에 공백이 작아도 Segment를 집어넣을 수 있다.
따라서 External Fragmentation
이 발생하기는 하지만, 생각처럼 자주 Compaction
을 할 필요는 없다.
주소는 paging과 마찬가지로 세그먼트 번호와 offset으로 나뉜다.
첫 번째 Segment는 750 bytes이다. 따라서 1502번지는 1번 Segment의 752 offset에 위치한다.
Segmentation 기법에서 Relative Address를 주고 Segmentation 시스템에서 사용하는 주소로 바꾸라고 한다면 Segment 크기를 확인해야 한다.
Segmentation 기법에서 Logical Address는 주소가 달라진다. 왜냐하면 나누는 것이 아니라 Segment 크기를 빼기 때문이다.
💡Segment Table의 한 Entry 길이?
한 Entry 에는 Length와 Base를 가지고 있다.
따라서, Segment Table 한 Entry의 길이 = Base + Length = Physical Address의 길이 + Segment의 길이 = 16 bit + 12 bit = 28 bits