학습목표
1. 주소 바인딩 개념을 설명할 수 있다.
2. 연속적인 메모리 할당의 장단점을 설명할 수 있다.
3. 페이징 기법을 설명할 수 있다.
4. 세그멘테이션 기법을 설명할 수 있다.
Contiguous Allocation
OS 메모리전략에 대해 키워드별로, 연속되게.
#1에 이어서, 여러 코드가 컴파일되어 메모리에 올라갔을 때, 하나의 라이브러리에 들어있는 함수와 변수를 참조할 수 있다. 하나의 라이브러리를 test1.c와 test2.c가 참조하는 상황을 보자. test1.c가 메모리에 올라갈때 이 라이브러리를 함께 load한 후, test2.c가 메모리에 올라갈 때 또 다시 똑같은 라이브러리를 메모리에 가져갈 수 있다. 하지만 낭비다. 어차피 참조하는 라이브러리는 하나이므로 한번만 메모리에 올려놓으면 test1.c, test2.c 등 여러개의 프로세스가 참조하게 할 수 있다. 이러한 메모리효율성 맥락에서 Dynamic Loading, Dynamic Linking을 사용할 수 있다.
Dynamic Loading : 메모리에서 같은 라이브러리를 참조하는 두 개의 프로그램이 돌 때, 중복된 메모리 사용을 줄이기 위해(Better memory-space Utilization) 일부 라이브러리 코드의 load를 미뤄뒤고 실행 도중 필요시, CPU 호출에 의해 로드되는 것이다. 그런데 메모리로 load할 때마다 메모리에서 매번 동일한 address가 비어있는 것이 아니기 때문에 dynamic linking이 필요하다.
Dynamic Linking : 링킹과정이 execution time까지 미뤄진다. 그리고나서 여러개의 프로세스가 필요로하는 하나의 라이브러리는 중복해서 메모리에 올리는 것이 아니라 하나의 라이브러리만을 올려놓고 공유하여 참조하는 것이다.
이제 조금 다른 관점에서 메모리관리 방법을 보자. 사용자의 메모리 하드웨어가 4GB라면 정말 4GB의 프로세스만 올려놓을 수 있을까?
NO!
다음과 같은 방법을 사용하면 사용자가 보기에 실제보다 더 많은 메모리를 사용하는 것 같은 효과를 낼 수 있다.
Swapping : 스와핑이란 메인메모리에 올라와 있는 프로세스를 임시로 보조메모리로 보내거나 가져오는 작업을 말한다. 스와핑을 사용하는 이유는 간단하다. CPU 효율과 같은 맥락에서 다중프로세스처리 때문이다. 스와핑이 없는 상태를 생각해보면 스와핑이 왜 필요한지 알 수 있다.
스와핑을 사용하지 않는다면 사용자는 딱 자신이 가진 메모리만큼만 프로세스를 돌릴 수 있을 것이다. RAM이 4GB라면 딱 4GB만큼의 프로세스만 돌릴 수 있다. 하지만 프로세스가 시간이 많이 걸리는 작업들(예를들어, I/O작업)을 하는 동안, Swap-out하고(프로세스를 메인메모리에서 보조메모리로 내리는 작업), 그 동안 다른 프로세스를 Swap-In(Swap-out의 반대)하여 작업할 수 있다면?
사용자는 자신이 가진 메모리보다 실제로는 더 많은 프로세스를 올려놓고 작업할 수 있는 것이다. 물론 메인메모리의 크기가 충분하다면 구지 안내려도 상관없지만 제한적이라면 사용자는 그리 떨어지지않는 성능으로 실제 메모리보다 더 많은 프로세스를 돌릴 수 있다. 여기서 더 생각할 것은 swapping 자체가 disk I/O 작업이라 시간이 오래걸리기 때문에 스케줄링 알고리즘이 그 만큼 중요하다는 것이다.
스케줄링을 보기 전에 메인메모리에 어떻게 할당하는 것이 효율적일까?
효율적인 메모리할당을 하려면 먼저 메모리가 크게 어떻게 구성되어있는지 알 필요가 있다.
먼저 Main memory는 OS파티션과 유저프로세스 파티션으로 나눠진다. 메모리에 상주하는 운영체제가 하위 메모리에 위치하고 사용자가 사용하는 메모리영역이 상위 메모리로 나눠진다. 그러므로 사용자가 프로세스를 돌리고자할 때, 상한 레지스터(limit register)에 저장된 주소값 이하라면 운영체제에게 할당된 메모리이므로 Address error를 발생시킨다. 운영체제가 사용하는 메모리를 침범하면 엉망진창이 되기 때문에 이렇게 한번 운영체제의 메모리영역인지 확인을 한 후 메모리의 기준인 재배치 레지스터(Relocation register)를 거치게 된다.
그럼 이제 OS파티션을 제외한 유저파티션에서 메모리를 최대한으로(효율적으로) 사용하기위해 어떻게 프로세스를 할당하는 것이 좋은지 생각해보자. 한가지 떠오르는 것은 빈 공간이 없이 꽉꽉 채워서 가능한 많은 프로세스를 담는 것이다.
Contiguous Memory Allocation : 메모리를 빈 공간없이 꽉꽉 채우려면 메모리의 처음부터 차곡차곡 쌓으면 된다. 그러나 문제는 프로세스를 빼고 넣는 과정에서 생긴다. 다음 그림과 같이 프로세스2, 4, 1 이 빠지고 들어오는 과정에서 빈 공간인 Hole이 생긴다. 마지막 (d)의 메모리구조에서 프로세스를 쪼개서 load할 수는 없으니 효율성이 떨어질 수 밖에 없다.
그렇기 때문에 프로세스를 메모리의 어떤 hole에 넣는 것이 가장 효율적일지 생각해 볼 수 있다. 리눅스 커널은 내부적으로 다음과 같은 자료구조를 갖고있다. 프로세스가 load된 메모리의 시작, 끝주소와 할당된 길이를 갖고있다.
이때, 리스트를 돌면서 다음과 같은 방식으로 load할 수 있다.
1. First-fit : load가능한 공간 중, 가장 첫번째의 공간에 할당하는 것.
2. Best-fit : load 가능한 공간 중, 가장 작은 공간에 할당하는 것.
3. Worst-fit : load 가능한 공간 중, 가장 큰 공간에 할당하는 것.
First-fit과 Best-fir이 Worst-fit 보다 시간과 메모리 이용 효율 측면에서 더 좋다는 것이 입증된 상태라고 한다.
단편화(Fragmentation) : 지금까지 메모리 할당 이슈를 보면 알겠지만, 결국 짜잘짜잘한 빈공간이 많아지면 빈공간이 많음에도 불구하고 연속된 빈공간이 없기 때문에 프로세스를 load할 수 없게된다. 이러한 것을 단편화(Fragmentation)이라고 한다. 이러한 단편화는 외부 단편화와 내부 단편화가 있다. 지금까지 말한 단편화는 사실 외부단편화를 의미하고 내부단편화는 메모리가 고정된 크기의 정수 배로 할당되어 할당된 공간이 요구된 공간보다 더 클 수 있다는 것이다. 내부단편화는 페이징이 무엇인지 알면 이해가 간다.
'Project > OS' 카테고리의 다른 글
10. main memory #1 : 주소바인딩에 대해서 (0) | 2017.11.30 |
---|