-
10일차 - Memory Management(1)CS지식/운영체제 2021. 5. 4. 23:42
오늘부터는 메모리를 어떻게 관리하는지에 대해 배웠다.
지난 시간동안 프로세스들이 CPU를 얻는 과정에서 발생하는 일들을 배웠는데 오늘은 프로세스가 실행되고 물리적인 메모리에 올라가면서 발생하는 일들 중 일부분을 배울 수 있었다.
1. memory management의 기본
우선 메모리 관리를 배우기 전에 메모리에 대해 잠깐 언급하자면 메모리는 주소를 통해 접근하는 매체이다.
여기서 주소는 logical address와 physical address로 나뉜다.
1) logical address
logical address는 가상주소(virtual address)와 같은 말로 프로세스마다 독립적으로 가지는 주소 공간이다.
각 프로세스마다 주소할당은 0번부터 시작한다.
2) physical address
physical address는 메모리에 실제로 올라가는 위치를 뜻한다. 즉, 프로세스가 실행되었을 때 올라간 메모리의 위치를 말하는 것이다.
이렇게 2가지의 주소 종류가 존재하게 되고 프로세스는 처음에 가상메모리에서 logical address인 독자적인 주소를 가지고 있지만 실행이 되려면 물리 메모리의 어딘가에 올라가야하고 그러면 주소가 physical address로 바뀌어야한다.
여기서 나오는 중요한 개념이 주소 바인딩이다. 주소 바인딩은 간단히 말해서 주소를 결정하는 것을 말하며 logical address가 physical address로 변환하는 과정이다.
그러면 주소 바인딩, 주소가 변환되는 시점은 언제일까?
2. 주소 바인딩
위에서 주소 바인딩이란 주소를 결정(변환)하는 것이라고 언급했다.
그리고 주소가 변환되는 시점은 언제인지 알아보면 총 3가지가 존재한다.
1) Compile time binding
compile time binding은 소스코드가 실행파일로 컴파일되는 시점에 이미 물리적 주소가 결정되는 것이다.
즉, 프로세스의 logical address 그대로 physical address가 되어 물리 메모리에 올라가게 된다.
만약, 물리적 메모리의 위치를 바꾸고 싶다면 컴파일을 다시해야 한다.
여기서 컴파일 후 정해진 주소가 프로세스의 logical address이지만 이것이 그대로 physical address로 고정되기 때문에 컴파일러가 절대코드(absoulte code)를 생성한다고 한다.
2) Load time binding
Load time binding은 프로세스가 시작(실행)되서 물리적 메모리에 올라갈 때 pyhsical memory가 결정된다.
항상 특정위치에 올라가야하는 것이 아닌 실행 시에 어느 위치든 올라갈 수 있어 이 때 컴파일러가 생성한 코드를
재배치가능코드라고 한다.
3) Execution time binding (Run time binding)
Execution time binding은 load time binding과 같이 프로세스가 실행 시에 physical address가 결정되는 것은 똑같다.
하지만, Execution time binding은 physical addressr가 실행 도중에 바뀔 수 있다는 것이 다르다.
이렇게 된다면 CPU는 주소를 참조할 때마다 binding을 점검할 필요가 있고 하드웨어적인 지원이 필요하게 된다.
3. Memory-Management Unit(MMU)
주소 바인딩에서 execution time binding을 할 때 하드웨어적인 지원이 필요하다고 설명했다.
그 중 하나가 MMU로 logical address를 physical address로 매핑해주는 하드웨어 장치이다.
MMU의 가장 기본적인 동작원리는 dynamic relocation으로 레지스터 2개를 사용하는 것이다.
여기서 사용하는 레지스터는 relocation(=base)register와 limit register가 있다.
relocation register의 기능은 프로세스가 물리적 메모리에 올라가 있는 시작 위치를 알려준다.
즉, CPU가 a번지 logical address를 요구하면 MMU가 a번지에 relocation register의 값을 더해서 변환된 주소를 알려주면 된다.
그러면 limit register의 역할은 무엇일까?
limit register는 프로세스의 최대 크기를 가지고 있다. 예를 들어 프로세스 a가 logical address 0번부터 3000번까지 있다면 최대 크기는 3000이 된다.
그러면 limit register는 왜 필요할까?
logical address가 physical address로 바뀔 때 logical address의 간격 그대로 physical address로 올라간다.
즉, logical address가 0, 10, 20, 30이라면 physical address에서 500, 510, 520, 530이렇게 올라간다.
이렇게 되었을 때 최대 크기가 3000인 프로세스가 악의적으로 자신의 주소 이외의 값, 예를 들어 4000을 달라고 요청했다고 해보자.
이러한 상황에서는 당연히 주면 안되므로 막기 위해 limit reigster의 값과 요청한 logical address의 주소와 비교하여 판단하게 되는 것이다.
4. Allocation of Physical memory
지금부터는 프로세스가 메모리에 실제로 올라갈 때 어떻게 할당되는지 알아보자.
먼저 메모리는 일반적으로 두 영역으로 나뉘어 사용된다.
하나는 OS 상주 영역으로 interrupt vector와 함께 낮은 주소영역을 사용한다.
다른 하나는 사용자 프로세스 영역으로 높은 주소 영역을 사용한다.
그러면 우리가 알아보아야 할 사용자 프로세스 영역의 할당 방법은 어떻게 될까?
할당 방법은 2가지로 분류되어 정의할 수 있다.
1) Contiguous allocation
각각의 프로세스가 메모리의 연속적인 공간에 적재되도록 하는 것
즉, 프로세스가 한꺼번에 메모리에 올라간다는 것이다.
2) Noncontiguous allocation
하나의 프로세스가 메모리의 여러 영역에 분산되어 올라갈 수 있는 방법이다.
5. Contiguous allocation
contiguous allocation에 대해서 더 자세히 알아보자.
contiguous allocation은 고정분할 방식과 가변분할 방식으로 나뉜다.
1) 고정분할 방식(Fixed partition)
고정분할 방식은 물리적 메모리를 몇 개의 영구적 분할로 미리 나누어 놓는 것이다.
여기서 물리적 메모리의 미리 분할할 때 분할의 크기가 모두 동일한 방식과 서로 다른 방식이 존재한다.
분할된 크기 하나 당 하나의 프로그램이 적재된다.
이 방법은 동시에 메모리에 load되는 프로그램 수가 고정되고 수행가능한 프로그램의 최대 크기가 제한되어 융통성이 없는 방법이다.
또한, Internal fragmentation과 external fragmentation이 발생할 수 있다.
External fragmentation은 외부조각으로 프로그램 크기보다 분할의 크기가 작은 경우 생기는 것이다.
즉, 빈 분할이 있지만 프로그램의 크기보다 작아 사용되지 못하는 공간을 의미한다.
Internal fragmentation은 내부조각으로 프로그램크기보다 분할의 크기가 큰 경우 생기는 것이다.
하나의 분할 내부에서 발생하는 사용되지 않는 메모리 조각을 의미한다.
2) 가변분할 방식
가변분할 방식은 프로그램의 크기를 고려해서 할당하는 것으로 분할의 크기, 갯수가 동적으로 변한다.
기술적 관리 기법이 필요하고 이 방법에서는 external fragmentation이 발생한다.
여기서 hole이라는 개념이 새롭게 도입된다.
- hole
hole은 가용메모리 공간을 의미하며 메모리에는 다양한 크기의 hole들이 여러 곳에 흩어져 있다.
프로세스가 도착하면 수용가능한 hole을 할당하고 운영체제는 할당되어있는 공간과 가용가능한 공간 정보를 유지해야한다.
이렇게 메모리에 다양한 크기의 hole이 존재하게 되면 프로세스가 접근했을 때 어느 hole에 할당해주는게 좋은지 판단해야할 것이다.
- Dynamic storage-allocation problem
가변 분할방식에서 size가 n인 프로세스를 메모리에 할당할 때 가장 적절한 hole을 찾은 문제이다.
이 문제를 해결하는 방법은 3가지가 존재한다.
1) First-fit
이 방법은 hole의 size가 프로세스의 size 이상인 것 중 최초로 찾아지는 hole에 할당하는 것이다.
2) Best-fit
이 방법은 hole의 size가 프로세스의 size 이상인 것 중에서 가장 작은 hole을 할당하는 것이다.
hole들의 리스트가 크기 순으로 정렬되지 않은 경우에는 모든 hole의 리스트를 탐색해야한다.
3) Worst-fit
이 방법은 그냥 단순히 지금 존재하는 hole중에 가장 큰 hole을 할당하는 것이다.
고정분할방식보다는 융통성있게 변화한 것같지만 크기가 애매한 hole을 이용할 수 있도록 hole들을 한 곳으로 모아서 유지하면 어떨까?
- Compaction
사용 중인 메모리 영역을 한 곳으로 몰고 hole들을 다른 한 곳으로 몰아 큰 hole을 만드는 것이다.
이 방법은 매우 비용이 많이 드는 방법이다.
compaction은 프로세스의 주소가 실행시간에 동적으로 재배치 가능한 경우에만 수행될 수 있다.
6. Paging
위에서는 contiguous allocation에 대해 알아보았다. 지금부터 noncontiguous allocation 중 하나인 paging에 대해 알아보자.
paging은 프로세스의 virtual memory를 동일한 사이즈의 page단위로 나누는 것이다. 이렇게 나뉜 virtual memory내의 page는 필요한 page만 그때 그때 noncontiguous하게 메모리에 올라간다.
paging을 하게 되면 앞에서 배운 Dynamic relocation을 통해서는 주소변환을 하지 못한다.
page마다 어디에 위치해있는지 알아야하기 때문에 page table을 참고하여 page가 물리적메모리의 어디에 위치해있는지 파악한다.
그러면 이 page table은 어디에 존재할까?
page table은 물리적 메모리에 존재한다. page table이 물리적 메모리에 존재하기 때문에 메모리 접근을 위해서는 2번의 메모리 접근이 필요해진다.
한번은 page table을 참고하기 위해 접근하고 한번은 변환된 physical address로 메모리에 접근하여 2번 접근하게 된다.
dynamic relocation에서는 base register와 limit register가 쓰인다고 배웠다.
paging을 사용하게 되면 주소 변환 할때에 Page-table base register(PTBR)과 Page-table length register(PTLR)이 쓰인다.
Page-table base register(PTBR)은 메모리 상에 page table의 위치를 알려주는 역할을 하고
Page-table length register(PTLR)은 페이지 테이블의 길이를 알려준다.
여기서 CPU가 매 번 메모리 접근을 위해 주소변환을 요청할 때마다 page table을 보고 변경해주는 것은 시간적으로 비효율적이다.
속도를 향상하기 위해 associative register 혹은 translation look-aside buffer(TLB)라 불리는 고속의 lookup hardware cashe을 사용한다.
- Associative Regiser
associative register를 사용하면 TLB에 CPU가 빈번하게 요청하는 것들을 저장해 놓는다.
즉, page table의 일부가 레지스터에 저장되어 있는 것이다.
만약 해당 page 번호가 associative register에 있는 경우에는 바로 frame 번호를 얻게 되고 그렇지 않은 경우에는 main memory에 있는 page table로부터 프레임 번호는 얻게 된다.
'CS지식 > 운영체제' 카테고리의 다른 글
12일차 - Virtual Memory (0) 2021.05.10 11일차 - Memory Management(2) (0) 2021.05.07 9일차 - Deadlock(교착상태) (0) 2021.05.01 8일차 - Process Syncronization(2) (0) 2021.04.28 7일차 - Process Syncronization(1) (0) 2021.04.25