memory를 나눌 때 어떻게 눌지 정해야 한다. 모든 프로세스는 메모리에 올라와서 실행되는데 각각의 프로세스는 자신만의 할당 메모리가 있다. 이때 하나의 프로세스가 다른 프로세스 메모리에 침범하면 문제가 생긴다.
이런 이유 때문에 메모리의 구분이 필수적이다.
예방하는 방법으로 가장 단순하게는 시작 주소와 끝 주소를 지정하는 것이다.
base 주소로부터 limit 주소를 하나의 프로세스에게 할당한다. (+아래서 보이지만, 운영체제 또한 메모리 상에 존재한다.)
어떤 프로세스를 할당할 때, base 주소보다 크고 base + limit 주소보다 작은 공간이 비어 있다면 할당하는 순서를 가질 수 있다.
Memory Address
메모리에는 Logical address와 Physical address가 존재한다. 이 차이를 알아보자,
Logical address는 간단히 말해 CPU에 의해 생성되는 Virtual address (가상 주소)다. 논리 메모리에 대해 간단한 설명은 아래 포스팅을 참조하면 좋겠다.
2022.06.08 - [내가 하는 공부/운영체제 (OS)] - 운영체제 Virtual Memory ( 간단한 개념 )
Physical address는 메모리 상에 존재하는 실제 주소다. 물리적인 주소로 Memory Management controler(unit)에 의해 생성된다. 줄여서 MMU라고 한다.
아래 그림에선 base 주소인 14000을 가상 주소인 346과 더하여 실제 물리 주소를 할당한다.
Dynamic Loading
메모리에는 한계가 있고 정해진 용량이 있다. 하지만 여러 프로그램을 돌린다면 분명 메모리 용량이 부족한 순간이 생길 것이다. 이럴 때 필요한 게 Dynamic Loading이다.
프로세스가 실행되면 메모리에 올라가서 실행되는데 이때 용량이 큰 프로세스라면 메모리에 올라가는데 시간이 많이 걸릴 것이다. 이런 상황에서 모든 프로그램이 올라갈 때까지 기다리는 게 아니라, 당장 필요한 부분 부분만 올려서 빨리 실행하겠다는 의미다.
동적으로 실행하겠다는 의미인데, 가령 예를 들어 코드를 실행할 때 모든 라이브러리를 불러오고 실행하는 것이 아니라 일단 먼저 main문을 실행하다가 printf() 같은 함수를 호출하면 그때 동적으로 메모리에 올려서 실행한다.
이런 걸 static linking이라고 부른다. 컴파일 시간에 결정되는 걸 말한다.
Memory Allocation
메모리를 어떻게 할당하는지 알아보기 전에, 메모리의 할당은 연속적이어야 한다는 전제를 깔고 시작한다.
이런 걸 Contiguous allocation이라 한다.
왜 연속적이어야 하냐면, 만약 16MB짜리 프로그램을 돌리는데 4MB는 메모리의 아래쪽, 12MB는 메모리의 위쪽에 존재한다면 각각의 데이터를 탐색하고 왔다 갔다 하는데 너무 overhead가 크다. 또한 캐시를 생각해보면 지역성을 고려하여 메모리를 load 하는데 연속적이 않다면, 효율이 최악이다.
자, 이제 메모리 할당을 어떻게 하는지 알아보자. 현재 사용하진 않지만 예전에는 어떻게 했냐면, 정해진 단위를 기준으로 할당했다.
예를 들면 기준이 4칸이라 하고 어떤 프로그램을 돌리는데 15칸이 필요하다면, 4칸을 할당해주는 Static allocation을 했다. 이렇게 하면 필요한 건 15칸이지만 할당한 건 16칸이니 1칸이 낭비된다. 이렇듯 할당 메모리 내부에 남는 공간을 못 쓰는 문제를 Internel Fragmentation ( 내부 단편화 )라고 부른다.
이런 문제들이 있으니 정해진 크기가 아니라 프로그램 단위로 메모리 할당을 해야 했다. 간단히 말해 static 한 할당이 아닌 variable (동적)하게 할당해야 한다. 이렇게 하면 internel fragmentation 문제가 없어질 것이라 생각했다.
여러 프로세스가 실행되다 보면 먼저 끝나는 프로세스들이 생긴다. 이때 빈 공간을 Hole이라고 부르는데, 이 Hole을 운영체제가 계속 추적하고 있다가 새로운 프로그램을 실행하면 hole 중에 하나를 선택하여 할당한다.
여러 Hole 중에 어떤 hole을 선택해야 효율이 더 좋을까??
어떤 hole을 선택할 것인가에 대해선 3가지 기준이 있다.
1. First Fit
- 새로운 프로그램이 들어가기에 큰 hole을 만나면 바로 이 hole에 할당한다. 이렇게 되면 internel fragmentation이 생길 수도 있다. 그러나 메모리를 다 탐색하지 않아도 되니 시간이 절약된다.
2. Best Fit
- 탐색 후에 가장 알맞게 들어가는 hole을 선택한다. 찾는데 너무 오랜 시간이 걸린다.
3. Worst Fit
- 탐색 후에 가장 큰 hole을 선택한다. 가장 좋지 않다.
하지만 문제가 생긴다.
어떤 문제냐, 만약 3개의 Hole이 존재하는데 각각 5MB의 크기를 가지고 있다고 하자, 그렇다면 전체 메모리는 15MB가 남는다. 이때 새로운 프로그램이 7MB일 때 전체 메모리는 수용하고도 남지만, 각각의 hole의 크기로는 작기 때문에 대기해야 하는 상황이 생긴다.
이렇듯 전체 메모리는 수용 가능 하지만 hole의 크기가 부족하여 할당할 수 없는 문제를 Externel Fragmentation (외부 단편화)이라고 부른다..
전체 메모리 = 할당 block + 빈 공간( or hole )
위와 같이 정의되는데 보통 1/3이 빈 공간으로 남는다. n개의 block이 할당됐다고 했을 때 0.5n block 정도가 Fragmentation 된다는 통계가 있다. (50% rule이라 부른다)
이렇게 물리 주소를 연속적으로 할당하니 문제가 많았다. 이런 이유 때문에 Paging이라는 개념이 나왔다.
paging에 대해선 다음에 올리겠다.
댓글