내가 ABCD란 곳에 데이터를 저장하고나서, 메모리에서 ABCD의 값을 읽으려면 ABCD의 위치를 알아야 한다. ABCD를 지정해야 하는데 어떻게 읽을 수 있을까??
메모리에 어딘가에 값이 지정되어 있는데 그 어딘가가 address
(데이터의 위치)이다.
우리가 우리집의 주소를 나타낼때 한가지 방법만 있는게 아니다.
도로명 주소도 있고, 지번주소도 있고, 위도, 경도로도 나타낼 수 있다.
우리나라의 도로명 주소나 지번주소를 쓸 수 있는 곳은 지구상에 우리나라 밖에 없다.
마찬가지로, 다른 나라들도 각자 나라들만의 address space
가 존재한다. 반면 위도 경도는 모든 지구상의 나라들이 통용되어 있다.
컴퓨터에서도 여러가지로 주소를 나타낼 수 있는 주소체계가 있다.
위도와 경도는 전세계적으로 통용되므로 실제적인 address라고 할 수 있다.
이처럼,physical address는 실제 data의 주소를 말한다.
우리는 실제로 주소를 찾을때 위도 경도로는 주소를 잘 찾지 않는다. 알아보기가 어렵기 때문이다. 그래서 우리는 지번주소(logical address)로 길을 찾곤한다.
컴퓨터에서도 Physical address가 모든 주소를 나타내지는 않고 이를 대체하는 logical address가 있다. logical address를 통해서 physical address를 좀 더 쉽게 나타내게 하는것이다.
예를 들어보자.
int a = 10;
int *b = &a;
a라는 변수에 10이 들어 있다. a 변수는 physical address에 10을 저장했다.
b는 a라는 변수에 주소를 갖는다. a의 주소를 표현하기만 되기 때문에 포인터b라는 새로운 변수로도 a를 나타낼수있다. 이러한 b를 logical address라고 한다.
Absolute address: 절대적인 위치를 직접 표현
relative address: 기준 주소를 가지고 상대적으로 주소 표현
process가 지정하고 있는 주소와 실제적으로 저장되어 있는 주소는 다르다.
cpu는 logical address를 다루고 실제적으로 데이터가 저장되는곳은 physical address이다.
이것을 가능하게 하는 것이 MMU(Memory Management Unit)이다. MMU가 logical address를 physical address로 변환해준다.
참고로, MMU는 main chip 옆에 붙어있는 하드웨어이다.
그렇다면 physical memory에 여러개의 logical memory를 겹치지 않게 어떻게 할당해주어야 할까??
process들에게 physical address의 일부분을 아예 지정해서 할당한다.
그렇다면 여러 프로세스가 있는데 어떻게 각 프로세스의 logical address를 할당을 할 수 있을까?? 밑에 그림을 보자.
logical address를 각 partition의 시작주소에 relative address로 사용했다.
즉,logical address에 Base register의 주소를 더해서 physical address로 할당하는 것이다. 이 역할을 해주는게 바로 MMU
이다. MMU는 각 프로세스의 base register의 주소를 알아내서 logical address와 더해서 physical address로 변환해준다.
참고: base register 주소는 PCB에 들어있다.
partition의 크기: 위그림에서 0x1000
process 간에 context switch도 쉽게 가능하다. 만약 logical address가 같더라도 process에 맞는 base register로 바꿔주면 되기 때문이다.
또한, logical address의 크기가 partition의 크기를 넘어갈수도 있는 상황을 방지하기 위해서 MMU는 logical address의 크기를 partiion의 크기 이하로 제한한다.
정리하자면 MMU는
1. logical address가 partition의 크기를 넘지 않는지 검사
2. logical address+base register address를 통해 physical address로 변환
fixed partition에 문제가 있다. partition 사이즈가 모두 일률적이기 때문에 proccess들이 메모리를 다 사용하지 못해서 발생하는 남는 메모리들이 각 process의 physical memory에서 많이 발생한다.(Internal Fragmentation)
구현으로 가보면 variable partition에서 운영체제가 관리해야 될것은 partition의 시작주소(base register)와 끝주소(limit register)이다. 그럼이제 MMU는 logical address를 base register의 주소와 더해서 physical address를 만들고 limit register와 비교한다. 만약 limit register를 넘어간다면 읽지 못하고 컴플레인을 한다.
base,limit register는 MMU에 저장됨
다른 형태로 limit을 관리하는 방법도 있다.
예를들어, process1의 partition의 크기는 0x1500이다. process1이 최대로 가질 수 있는 메모리의 크기가 0x1500인 것이다. 따라서, logical address가 0x1500을 넘지 않는다면 base register와 더해서 physical address로 변환하는 방법이 그것이다. (segmentation에서 사용)
process들이 할당을 받고 process2와 process4가 실행을 끝냈고 해당 메모리는 빈공간으로 남았다. 다음 process X가 메모리를 할당받고 싶은데, 두개의 hole보다는 메모리 크기가 크고, 두개의 hole을 합친정도에 메모리를 받고 싶은데 받을수 없다. 이것을 External fragmentation
이라고 한다.
위 경우는 process X가 메모리를 할당 받아야 하는데 두개의 hole 모두가 공간이 충분한 경우이다. 위에 hole은 processX가 할당 받는다면 나머지 memory가 조그만한게 만들어질 것이고(best fit), 밑에 hole의 메모리를 할당 받는다면 큰 memory 조각이 만들어질 것이다(worst fit). 이것은 할당 정책에 따라 어떤 것을 할당받을지는 다르다. 그러면 memory가 조금만 남는 best fit이 좋은 것일까?? 통계적으로 best fit일때 external fragmentation이 50%나 된다고 한다.
예상외로 best fit이 worst case가 되고,worst case가 best fit이 된다.
한 프로세스에게 하나의 partition을 주다보니까 fixed 이건 variable 이건 fragmentation은 항상 생긴다. 어차피 process address space는 stack,heap,data,code 다른 영역으로 나눠진다. process하나당 하나의 partition을 줄 필요없이 여러개의 partition을 주는게 어떨까?? 즉, variable partition의 확장으로, process address space를 여러개의 segment로 쪼개고, 각각을 따로따로 여기저기 놓자고 하는 게 segmentation이다.
variable partition 에서는 하나의 base,limit register의 주소를 알면 됐지만,
segmentation에서는 각 segment별로 파악해야 한다. 또한 variable partition에서는 limit register의 주소가 physical address였지만, segmentation에서는 limit이 offset의 최대 length로 나타내어 진다.
1.virtual address가 sement 1번의 0x0362를 읽고 싶어한다.
2.limit과 비교해서 offset이 최대 length를 벗어나는지 확인한다.
3.벗어나지 않는다면 base와 더해서 physical address의 주소를 읽는다.
문제는, segment table의 크기가 엄청 클텐데 이걸 다쓰기에는 자원이 넉넉하지 않고 A process에서 B process로 context switch가 되었을때, segment 정보를 하나하나 읽어서 B process 정보로 바꿔줘야 한다.(context switch 오버헤드가 너무 큼)
그래서, 보통 segment table 전체가 메모리에 있는 PCB에 들어가 있고 MMU가 참조하고 있는 STBR(segment table base register)이 현재 process의 segment table을 포인터로 가리키고 있다.
만약 context switch가 일어난다면, MMU가 STBR을 확인해서 현재 프로세스의 segment table을 메모리에서 읽어온다. 따라서, context switch를 했을때 STBR만 바꿔주면 해당하는 process의 segment table을 읽을 수 있다.
하지만, 연속적으로 memory를 할당할때 segmentation은 결국 external fragment를 해결할 수 없다. 그에 대한 해결 방안으로 나온게 paging이다.
paging은 밑에 링크에 있다.
https://velog.io/@tg-96/%EC%9A%B4%EC%98%81%EC%B2%B4%EC%A0%9CPaging-and-Page-Tables