메모리 관리
컴퓨터 내에서는 byte 단위로 메모리 주소를 부여하기 때문에 32 비트 주소 체계를 사용하면 2^32 바이트만큼의 메모리 공간에 서로 다른 주소를 할당할 수 있다. 컴퓨터상의 주소는 32비트를 그대로 사용하지 않고 효율적인 운영을 위해 연속된 일련의 영역을 행정구역처럼 묶어서 사용한다. 보통 4KB(2^12byte) 단위로 묶어서 페이지라는 하나의 행정구역을 만든다. 페이지 하나의 크기가 2^12 바이트이므로 페이지 내에서 바이트별 위치 구분을 위해서는 12비트가 필요하다. 따라서 총 32비트의 주소 중 하위 12비트는 페이지 내에서의 주소를 나타내게 된다. 이번 장은 메모리를 어떠한 행정구역으로 나누어 관리하고 어떻게 물리적 메모리에 올라가서 주소를 할당받는지 본다.
주소 바인딩
프로그램이 실행을 위해 메모리에 적재되면 그 프로세스를 위한 독자적인 주소 공간이 생성된다. 이 주소를 논리적 주소 혹은 가상 주소
논리적 주소는 각 프로세스마다 독립적으로 할당되며 0번지부터 시작된다.
반면 물리적 주소는 물리적 메모리에 실제로 올라가는 위치를 말한다. 보통 물리적 메모리의 낮은 주소영역에는 운영체제가 올라가고, 높은 주소영역에는 사용자 프로세스들이 올라간다.
프로세스의 논리적 주소를 물리적 메모리 주소로 연결시켜주는 작업을 주소 바인딩이라고 한다.
주소 바인딩의 방식은 프로그램이 적재되는 물리적 메모리의 주소가 결정되는 시기에 따라 세 가지로 분류할 수 있다.
먼저 물리적 메모리 주소가 프로그램을 컴파일할 때 결정되는 주소 바인딩 방식을 컴파일 타임 바인딩 이라고 부른다. 이 방식은 컴파일을 하는 시점에 해당 프로그램이 물리적 메모리의 몇 번지에 위치할 것인지를 결정한다. 절대코드를 생성하는 바인딩 방식이라고 말하기도 한다. 이와 같은 방식은 물리적 메모리의 위치를 변경하고 싶다면 컴파일을 다시 해야한다. 따라서 비현실적이고 현대의 시분할 컴퓨팅 환경에서는 잘 사용하지 않는다.
두 번째는 실행이 시작될 때 물리적 메모리 주소가 결정되는 주소 바인딩 방식을 로드 타임 바인딩이라고 한다. 이 방식은 로더의 책임하에 물리적 메모리 주소가 부여되며 프로그램이 종료될 때까지 물리적 메모리상의 위치가 고정된다. 로더란 사용자 프로그램을 메모리에 적재시키는 프로그램을 말한다. 로드 타임 바인딩은 컴파일러가 재배치 가능 코드를 생성한 경우에 가능한 주소 바인딩 방식이다.
세 번째는 프로그램이 실행을 시작한 후에도 그 프로그램이 위치한 물리적 메모리상의 주소가 변경될 수 있는 실행시간 바인딩 방식이다.
이 방식에서는 CPU가 주소를 참조할 때마다 해당 데이터가 물리적 메모리의 어느 위치에 존재하는지, 주소 매핑 테이블을 이용해 바인딩을 점검해야 한다. 그리고 기준 레지스터와 한계 레지스터를 포함해 MMU(Memory Management Unit: 메모리 관리 유닛)라는 하드웨어적인 지원이 뒷받침되어야 한다. MMU는 논리적 주소를 물리적 주소로 매핑해주는 하드웨어 장치이다.
CPU가 특정 프로세스의 논리적 주소를 참조하려고 할 때 MMU 기법은 그 주소값에 기준 레지스터의 값을 더해 물리적 주소값을 얻어낸다. 이때 기준 레지스터는 재배치 레지스터라고도 부르며 그 프로세스의 물리적 메모리 시작 주소를 가지고 있다. MMU 기법에서는 프로그램의 주소 공간이 물리적 메모리의 한 장소에 연속적으로 적재되는 것으로 가정한다.
EX) 논리적 주소가 123번지고 기준 레지스터가 23000일 때, 물리적 주소는 이 둘을 더한 23123을 참조하게 된다. 논리적 주소는 물리적 메모리의 시작 위치인 재배치 레지스터값으로부터 요청된 위치가 얼마나 떨어져 있는지를 나타내는 일종의 오프셋 개념으로 생각할 수 있다. MMU 기법에서는 문맥교환으로 CPU에서 수행 중인 프로세스가 바뀔 때마다 재배치 레지스터의 값을 그 프로세스에 해당되는 값으로 재설정함으로써 각 프로세스에 맞는 서로 다른 100번지 위치에 접근하는 것을 지원한다.
MMU 방식을 사용하는 도중 주소 변환을 했을 때에 CPU가 요청한 논리적 주소값과 재배치 레지스터 안에 있는 값의 합이 프로세스의 주소 공간을 벗어나는 경우가 발생할 수 있다. 한 프로세스가 다른 메모리 영역을 침범하는 경우를 막기위해 한계 레지스터라는 레지스터를 두어 주소 공간을 넘어서는 메모리 참조를 하는지 체크할 수가 있다. 논리적 주소가 한계 레지스터값 보다 크다면 트랩을 발생시켜 해당 프로세스를 강제 종료시키는 절차가 추가된다.
메모리 관리와 관련된 용어
동적로딩
동적로딩(dynamic loading)은 여러 프로그램이 동시에 메모리에 올라가서 수행되는 다중 프로그래밍 환경에서 메모리 사용의 효율성을 높이기 위해 사용하는 기법 중 하나이다. 지금까지 프로세스 실행 시에 프로세스의 주소 공간 전체를 메모리에 적재되는 환경을 가정했지만, 동적로딩은 해당 부분이 불릴 때 그 부분만은 메모리에 적재하는 방식을 사용한다. 실제로 프로그램의 코드 중 상당 부분은 오류 처리루틴과 같이 아주 특별한 경우에만 가끔씩 사용되는 방어용 코드이기에 메모리의 낭비가 초래된다. 동적로딩은 운영체제의 특별한 지원 없이 프로그램 자체에서 구현이 가능하며 운영체제가 라이브러리를 통해 지원할 수도 있다.
동적연결
연결(linking)은 프로그래머가 작성한 소스 코드를 컴파일하여 생성된 목적 파일(object file)과, 이미 컴파일된 라이브러리 파일들을 묶어 하나의 실행파일을 생성하는 과정을 말한다. 동적 연결(dynamic linking)은 컴파일을 통해 생성된 목적 파일과 라이브러리 파일 사이의 연결을 프로그램의 실행 시점까지 지연시키는 방법이다. 정적연결(static linking)과는 다르게 동적연결에서는 라이브러리가 실행 시점에 연결된다. 즉 실행파일에 라이브러리 코드가 포함되지 않으며, 프로그램이 실행되면서 라이브러리 함수를 호출할 때가 되어서야 라이브러리에 대한 연결이 이루어진다. 동적연결을 가능하게 하기 위해 실행파일의 라이브러리 호출 부분에 해당 라이브러리의 위치를 찾기 위한 스텁(stub)이라는 작은 코드를 둔다. 라이브러리 호출 시 스텁을 통해 해당 라이브러리가 메모리에 이미 존재하는지 살펴보고 그럴 경우 그 주소의 메모리 위치에서 직접 참조하며, 그렇지 않을 경우 디스크에서 동적 라이브러리 파일을 찾아 메모리로 적재한 후 수행하게 된다. 동적연결에서는 다수의 프로그램이 공통으로 사용하는 라이브러리를 메모리에 한 번만 적재하므로 메모리 사용의 효율성을 높일 수 있다. 이러한 동적연결 기법은 운영체제의 자원을 필요로 한다.
중첩
중첩(overlays)이란 프로세스의 주소 공간을 분할해 실제 필요한 부분만을 메모리에 적재하는 기법을 말한다. 동적로딩과 개념적으로 유사하다. 중첩은 초창기 프로세스조차도 메모리에 한꺼번에 올릴 수 없을 때, 프로세스의 주소 공간을 분할해서 당장 필요한 일부분을 메모리에 올려 실행하고 해당 부분에 대한 실행이 끝난 후에 나머지 부분을 올려 실행하는 기법을 뜻한다. 즉 프로그램의 크기가 물리적 메모리의 크기에 비해 작다면 주소 공간 전체를 한꺼번에 올릴 수 있지만 그렇지 않다면 분할해 메모리에 올리는 것이다. 반면 동적로딩에서는 다중 프로그래밍 환경에서 메모리의 이용률을 향상시키기 위한 것이라는 점에서 다르다. 즉 동적로딩은 메모리에 더 많은 프로세스를 동시에 올려놓고 실행하기 위한 용도인 반면, 중첩은 단일 프로세스만을 메모리에 올려놓는 환경에서 메모리 용량보다 큰 프로세스를 실행하기 위한 어쩔 수 없는 선택이었다.
스와핑
스와핑(swapping)이란 메모리에 올라온 프로세스의 주소 공간 전체를 디스크의 스왑 영역에 일시적으로 내려놓는 것을 말한다. 이때 스왑 영역은 백킹스토어(backing store)라고도 부르며, 디스크 내의 파일 시스템과는 별도로 존재하는 일정 영역을 말한다.
스왑 영역은 다수의 사용자 프로세스를 담을 수 있을 만큼 충분히 큰 저장공간이어야 하고 어느 정도의 접근 속도가 보장되어야 한다.
디스크에서 메모리로 올리는 작업을 스왑 인, 내리는 작업을 스왑 아웃이라고 부른다. 스와핑의 가장 중요한 역할은 메모리에 존재하는 프로세스의 수를 조절하는 것이다. 즉 스와핑을 통해 다중 프로그래밍의 정도를 조절하는 것이다. 너무 많은 프로그램이 메모리에 동시에 올라오게 되면 프로세스당 할당되는 메모리의 양이 지나치게 적어져 시스템 전체 성능이 크게 떨어진다.
컴파일 타임 바인딩 방식과 로드 타임 바인딩 방식에서는 스왑 아웃된 프로세스가 스왑 인 될 경우 원래 존재하던 메모리 위치로 다시 올라가야하나, 실행시간 바인딩 기법에서는 추후 빈 메모리 영역 아무 곳에나 프로세스를 올릴 수 있다.
스와핑에서 스왑 영역에 프로세스의 주소 공간이 순차적으로 저장되기 때문에 스와핑에 소요되는 시간은 디스크의 탐색시간이나 회전지연시간보다는 디스크 섹터에서 실제 데이터를 읽고 쓰는 전송시간이 대부분을 차지한다.
물리적 메모리의 할당 방식
사용자 프로세스 영역의 관리 방법은 프로세스를 메모리에 올리는 방식에 따라 연속할당(contiguous allocation)방식과 불연속할당(noncontiguous allocation)방식으로 나누어볼 수 있다.
연속할당 방식은 각각의 프로세스를 물리적 메모리의 연속적인 공간에 올리는 방식이다. 이 방식에서는 물리적 메모리를 다수의 분할로 나누어 하나의 분할에 하나의 프로세스가 적재되도록 한다. 이때 분할을 관리하는 방식에 따라 고정분할 방식과 가변분할 방식으로 나뉘는데, 고정분할 방식은 물리적 메모리를 고정된 크기의 분할로 미리 나누어두는 방식이고, 가변분할 방식은 분할을 미리 나누어놓지 않은 채 프로그램이 실행되고 종료되는 순서에 따라 분할을 관리하는 방식이다.
불연속할당 방식은 하나의 프로세스를 물리적 메모리의 여러 영역에 분산해 적재하는 방식이다. 불연속할당에는 각 프로세스의 주소 공간을 동일한 크기의 페이지로 잘라서 메모리에 페이지 단위로 적재시키는 페이징 기법과 프로그램의 주소 공간을 코드,데이터,스택 등 의미있는 단위인 세그먼트로 나누어 세그먼트 단위로 적재하는 세그먼테이션 기법, 세그먼트 하나를 다수의 페이지로 구성하는 페이지드세그먼테이션 기법 등이 있다.
연속할당 방식
연속할당 방식은 프로세스를 메모리에 올릴 때 그 주소 공간을 여러 개로 분할하지 않고 물리적 메모리의 한 곳에 연속적으로 적재하는 방식이다. 이 방식은 고정분할 방식과 가변분할 방식으로 나뉜다.
고정분할 방식
물리적 메모리를 주어진 개수만큼의 영구적인 분할로 미리 나누어두고 각 분할에 하나의 프로세스를 적재해 실행시킬 수 있게 한다. 이때 분할의 크기는 모두 동일하게 할 수도 있고 서로 다르게 할 수도 있지만 하나의 프로그램만을 적재한다는 점은 동일하다. 이 방식은 동시에 메모리에 올릴 수 있는 프로그램의 수가 고정되어 있으며 수행 가능한 프로그램의 최대 크기 또한 제한된다는 점에서 가변분할 방식에 비해 융통성이 떨어진다. 그리고 외부조각과 내부조각이 발생할 수 있다.
외부조각: 프로그램의 크기보다 분할의 크기가 작은 경우 분할이 비어 있는데도 불구하고 프로그램을 적재하지 못하기 때문에 발생하는 메모리 공간을 의미한다. 이 조각은 특정 프로그램에 배당된 공간이 아니기 때문에 이 조각보다 작은 프로그램이 도착한다면 외부조각에 적재시킬 수 있다.
내부조각: 프로그램의 크기보다 분할의 크기가 큰 경우 프로그램을 적재하고 남는 메모리 공간을 뜻한다. 충분히 작은 크기의 프로그램이 있어도 이미 특정 프로그램에 배당된 공간이므로 활용할 수가 없다.
가변분할 방식
가변분할 방식은 고정분할 방식과 달리 메모리에 적재되는 프로그램의 크기에 따라 분할의 크기, 개수가 동적으로 변하는 방식을 말한다. 가변분할 방식에서 분할의 크기를 프로그램의 크기보다 일부러 크게 할당하지는 않기 때문에 내부조각은 발생하지 않는다. 하지만 이미 메모리에 존재하는 프로그램이 종료될 경우 중간에 빈 공간이 발생하게 되며, 이 공간이 새롭게 시작되는 프로그램의 크기보다 작을 경우 외부조각이 발생할 가능성이 있다.
가변분할 방식에서는 크기가 n인 프로세스를 메모리에 올릴 때 물리적 메모리 내 가용 곤간 중 어떤 위치에 올릴 것인지에 대한 문제가 쟁점 중 하나이다. 이를 동적 메모리 할당 문제라고도 부른다. 연속할당 기법에서는 새로운 프로세스를 메모리에 올리기 위해 프로세스의 주소 공간 전체를 담을 수 있는 가용 공간을 찾아야 한다. 운영체제는 이미 사용 중인 메모리 공간과 사용하고 있지 않은 가용 공간에 대한 정보를 각각 유지하고 있다.
동적 메모리 할당 문제를 해결하는 대표적 방법으로 3가지가 있다.
첫 번째 방법은 크기가 n 이상인 가용 공간 중 가장 먼저 찾아지는 곳에 프로세스를 할당하는 최초적합(first-fit) 방법이다.
이 방법은 가용 공간을 모두 탐색하는 방법이 아니므로 시간적인 측면에서 효율적이다.
두 번째 방법은 크기가 n 이상인 가장 작은 가용 공간을 찾아 그곳에 새로운 프로그램을 할당하는 최적적합(best-fit) 방법이다.
이 방법은 가용 공간들의 리스트가 크기순으로 정렬되어 있지 않은 경우에 모든 가용 공간리스트를 탐색해야 하므로 시간적 오버헤드가 발생하고 다수의 매우 작은 가용 공간들이 생성될 수 있다는 단점이 있지만 공간적인 측면에서 효율적이다.
마지막으로 가용 공간 중에서 가장 크기가 큰 곳에 새로운 프로그램을 할당하는 최악적합(worst-fit) 방법이 있다.
이 방법은 최적적합 방법과 마찬가지로 모든 가용 공간 리스트를 탐색해야 하는 오버헤드가 발생한다. 또한 상대적으로 더 큰 프로그램을 담을 수 있는 가용 공간을 빨리 소진한다는 문제점이 있다.
실험결과에 따르면 최초적합과 최적적합 방식이 최악적합 방식에 비해 속도와 공간 이용률 측면에서 효과적인 것으로 알려져 있다.
가변분할 방식의 외부조각 문제를 해결하기 위한 방법으로 컴팩션(compaction)이라는 것이 있다. 사용 중인 메모리 영역을 한쪽으로 몰고 가용 공간들을 다른 한쪽으로 모아서 큰 가용 공간을 만드는 방법인데, 비용이 매우 많이 드는 작업이다. 따라서 가급적 적은 수의 메모리 이동으로 효율적인 컴팩션을 수행하는 방법이 필요한데, 이는 이론적으로 매우 복잡한 문제이다. 그리고 실행시간 바인딩 방식이 지원되는 환경에서만 수행될 수 있을 것이다.
불연속할당 기법
불연속할당 기법이란 하나의 프로세스가 물리적 메모리의 여러 위치에 분산되어 올라갈 수 있는 메모리 할당 기법을 말한다. 페이지 기법과 세그먼테이션 기법, 페이지드 세그먼테이션 기법 등이 있다.
페이징 기법
페이징 기법이란 프로세스의 주소 공간을 동일한 크기의 페이지 단위로 나누어 물리적 메모리의 서로 다른 위치에 페이지들을 저장하는 방식을 말한다. 페이징 기법에서는 각 프로세스의 주소 공간 전체를 물리적 메모리에 한꺼번에 올릴 필요가 없으며, 일부는 백킹스토어, 일부는 물리적 메모리에 혼재시키는 것이 가능하다. 페이징 기법에서는 물리적 메모리를 페이지와 동일한 크기의 프레임으로 미리 나누어둔다. 이는 메모리에 올리는 단위가 동일한 크기의 페이지 단위이므로, 메모리를 같은 크기로 미리 분할해두더라도 빈 프레임이 있으면 어떤 위치이든 사용될 수 있기 때문이다. 페이징 기법은 동적 메모리 할당 문제가 발생하지 않는다는 장점을 가진다. 페이징 기법은 주소 변환 절차가 연속할당 방식에 비해 다소 복잡하다. 논리적 주소를 물리적 주소로 변환하는 작업이 페이지 단위로 이루어져야 하기 때문이다. 즉 특정 프로세스의 몇 번째 페이지가 물리적 메모리의 몇 번째 프레임에 들어 있다는 페이지별 주소 변환 정보를 유지하고 있어야 하기 때문에 주소 변환을 위한 페이지 테이블을 모든 프로세스가 가진다. 페이지 단위로 이루어지기 때문에 외부조각 문제는 발생하지 않지만 프로그램의 크기가 항상 페이지 크기의 배수가 된다는 보장이 없기 때문에 프로세스의 주소 공간 중 제일 마지막에 위치한 페이지에서는 내부조각이 발생할 가능성이 있다.
주소 변환 기법
CPU가 사용하는 논리적 주소를 페이지 번호(p)와 페이지 오프셋(d)으로 나누어 주소변환에 사용한다. 페이지 번호는 각 페이지별 주소 변호나 정보를 담고 있는 페이지 테이블 접근 시 인덱스로 사용되고, 해당 인덱스의 항목에는 그 페이지의 물리적 메모리상의 기준 주소, 즉 시작 위치가 저장된다. 따라서 특정 프로세스의 p번째 페이지가 위치한 물리적 메모리의 시작 위치를 알고싶다면 해당 프로세스의 페이지 테이블에서 p번째 항목을 찾아보면 된다. 기준 주소값에 오프셋을 더해 요청된 논리적 주소에 대응하는 물리적 주소를 얻을 수 있다.
페이지 테이블의 구현
페이지 테이블은 페이징 기법에서 주소 변환을 하기 위한 자료구조로, 물리적 메모리에 위치하게 된다. 현재 CPU에서 실행 중인 프로세스의 페이지 테이블에 접근하기 위해 운영체제는 2개의 레지스터를 사용하는데, 이들은 각각 페이지 테이블 기준 레지스터와 페이지 테이블 길이 레지스터로 불린다. 기준 레지스터는 메모리 내에서 페이지 테이블의 시작 위치를 가리키며, 길이 레지스터는 페이지 테이블의 크기를 보관한다. 페이징 기법에서는 페이지 테이블에 접근하는 것과 변환된 주소에서 실제 데이터에 접근하는 총 2번의 메모리 접근을 필요로 한다. 두 번 접근해야 되는 오버헤드를 줄이기 위해 TLB(Translation Look-aside Buffer)라고 불리는 고속의 주소 변환용 하드웨어 캐시가 사용되기도 한다. 메모리에 비해 비싸기 떄문에 빈번히 참조되는 페이지에 대한 주소 변환 정보만을 담게 된다. 주소 변환 정보는 프로세스별로 다 다르기 때문에 문맥교환 시 이전 프로세스의 변환 정보를 담고 있던 TLB 내용은 모두 지워버려야 한다.
TLB는 페이지 테이블과 달리 모든 페이지에 대한 정보를 갖고 있지는 않기 때문에 페이지 번호와 프레임 번호가 쌍으로 저장되어야 하고 해당 페이지에 대한 주소 변환 정보가 TLB의 모든 항목을 다 찾아봐야 하는 오버헤드가 발생한다. 이러한 오버헤드를 줄이기 위해 TLB의 구현에는 일반적으로 병렬탐색이 가능한 연관 레지스터를 사용한다. 병렬탐색이란 TLB 내의 모든 항목을 동시에 탐색할 수 있는 기능을 말한다.
계층적 페이징
32비트 주소 체계를 사용하는 컴퓨터에서는 4GB의 주소 공간을 갖는 프로그램을 지원할 수 있다. 이러한 환경에서 페이지 크기가 4KB라면 1M개의 페이지 테이블 항목이 필요하게 되고, 각 페이지 테이블 항목이 4byte씩 필요로 한다면 한 프로세스 당 4MB의 크기의 메모리 공간이 필요하게 된다. 수행 중인 프로세스의 수가 증가함에 따라 페이지 테이블에 할애되는 메모리가 크게 증가할 것이다.
이를 위해 2단계 페이징을 기법을 사용한다. 외부 페이지 테이블과 내부 페이지 테이블을 사용한다. 사용되지 않는 주소 공간에 대해서는 외부 페이지 테이블의 항목을 NULL로 설정하여 대응하는 내부 페이지 테이블을 생성하지 않는 것이다. 이러면 1개만 사용하는 것에 비해 메모리의 낭비를 크게 줄일 수 잇지만 주소 변환을 위해 접근해야 하는 페이지 테이블의 수가 증가하므로 시간적인 손해가 뒤따른다.
논리적 주소로 두 종류의 페이지번호와 페이지 오프셋으로 구분한다. 첫 번째 페이지 번호는 외부 페이지 테이블의 인덱스이고, 두 번째는 내부 페이지 테이블의 인덱스이다. 두 번째 테이블로 부터 얻은 프레임으로부터 오프셋 만큼 떨어진 곳에서 원하는 정보를 얻을 수 있다.
역페이지 테이블
모든 프로세스의 모든 페이지에 대해 페이지 테이블 항목을 구성해야 하는 이유로 메모리 공간이 있었지만 이를 위한 대안으로 역페이지 테이블 기법이 사용될 수 있다. 각 프로세스마다 페이지 테이블을 두지 않고, 시스템 전체에 페이지 테이블을 하나만 두는 방법을 말한다. 페이지 테이블의 각 항목은 어느 프로세스의 어느 페이지가 이 프레임에 저장되었는지의 정보를 보관한다.
페이지 테이블은 프로세스 번호 pid 와 프로세스 내의 논리적 페이지 번호 p를 담고 있게 된다. 이제 그 위치만큼에 오프셋을 더하는 방식이다. 역페이지 테이블에서의 주소 변환은 다소 비효율적인 측면이 있다. 역페이지 테이블에 주소 변환 요청이 들어오면, 그 주소를 담은 페이지가 물리적 메모리에 존재하는지 여부를 판단하기 위해 페이지 테이블 전체를 다 탐색해야 하는 어려움이 있다. 그래서 역페이지 테이블은 일반적으로 메모리에 유지하는 대신 연관 레지스터에 보관해서 병렬탐색을 가능하게 하는 편이다.
공유 페이지
공유 코드는 메모리 공간의 효율적인 사용을 위해 여러 프로세스에 의해 공통으로 사용될 수 있도록 작성된 코드를 말한다. 공유 코드는 재진입 가능 코드 또는 순수 코드라고도 불리며 읽기전용(read-only)의 특성을 가지고 있다. 공유 페이지란 공유 코드를 담고 있는 페이지를 말한다. 공유 페이지는 여러 프로세스에 의해 공유되는 페이지이므로 물리적 메모리에 하나만 적재되어 메모리를 좀 더 효율적으로 사용할 수 있게 한다.
메모리 보호
페이지 테이블의 각 항목에는 주소 변환 정보뿐 아니라 메모리 보호를 위한 보호비트와 유효-무효 비트를 두고 있다.
보호비트는 각 페이지에 대한 접근 권할의 내용을 담고 있다. 한 프로세스의 주소 공간은 다른 프로세스에 의해 접근될 수 없으므로 '누구'에 해당하는 접근 권한을 설정할 필요는 없으며, 각 페이지에 대해 '어떠한' 접근을 허용하는지의 정보가 보호비트에 저장된다.
즉 보호비트는 각 페이지에 대해 읽기-쓰기/읽기전용 등의 접근 권한을 설정하는 데에 사용된다.
유효-무효 비트는 해당 페이지의 내용이 유효한지에 대한 내용을 담고 있다. '유효'로 세팅되어 있으면 해당 메모리 프레임에 그 페이지가 존재함을 뜻하며, 접근이 허용된다. 반면 '무효'로 세팅되어 있는 경우 해당 페이지가 물리적 페이지에 올라와 있지 않고 백킹 스토어에 존재해 해당 메모리 프레임에 유효한 접근 권한이 없다는 의미를 지닌다.
세그먼테이션
프로세스의 주소 공간을 세그먼트로 나누어 물리적 메모리에 올리는것이 세그먼테이션 기법이다.
하나의 프로세스를 구성하는 주소 공간은 일반적으로 코드, 스택, 데이터 등의 의미 있는 단위들로 구성된다. 세그먼트는 이 주소 공간을 기능 단위 또는 의미 단위로 나눈 것을 뜻한다. 크게는 프로세스의 주소 공간 전체를 하나의 세그먼트로 볼 수도 있으며, 많게는 프로그램을 구성하는 함수 하나하나를 각각 세그먼트로 정의할 수도 있다. 주의할 점은 크기 단위가 아닌 논리적인 단위로 나눈 것이기 때문에 그 크기가 균일하지 않다는 점이다.
세그먼테이션 기법에서는 논리적 주소가 <세그먼트 번호,오프셋>으로 나뉘어 사용된다. 세그먼트 번호는 논리적 주소가 프로세스 주소 공간 내에서 몇 번째 세그먼트에 속하는지를 나타내며, 오프셋은 그 세그먼트 내에서 얼마만큼 떨어져 있는지에 대한 정보를 나타낸다.
세그먼테이션 기법에서는 주소 변환을 위해 세그먼트 테이블을 사용한다. 그 안에는 기준점(base)과 한계점(limit)을 가지고 있다. 기준점은 물리적 메모리에서 그 세그먼트의 시작 위치를 나타내고, 한계점은 그 세그먼트의 길이를 나타낸다. 페이징 기법에서는 모든 페이지의 길이가 동일하므로, 페이지 테이블의 항목에 기준점이라 할 수 있는 페이지 프레임 위치만 유지하고 있으면 됐지만 세그먼테이션은 길이가 균일하지 않으므로 세그먼트의 위치 정보(이게 base)뿐만 아니라 길이 정보(이게 limit)를 함께 보관하고 있는 것이다.
페이징 기법에서 페이지 테이블 기준 레지스터와 페이지 테이블 길이 레지스터의 도움을 받았듯이,
세그먼테이션 기법에서도 세그먼트 테이블 기준 레지스터와 세그먼트 테이블 길이 레지스터로 사용하게 된다.
세그먼트 테이블 기준 레지스터는 현재 CPU에서 실행 중인 프로세스의 세그먼트 테이블이 메모리의 어느 위치에 있는지 그 시작 주소를 담고 있으며, 세그먼트 테이블 길이 레지스터는 그 프로세스의 주소 공간이 총 몇개의 세그먼트로 구성되는지, 즉 세그먼트의 개수를 나타낸다.
논리적 주소를 물리적 주소를 변환하는 과정에서 먼저 요청된 세그먼트 번호가 세그먼트 테이블 길이 레지스터보다 크다면 존재하지 않는 세그먼트에 대한 접근 시도이므로 예외상황을 발생시켜 메모리에 대한 접근을 봉쇄하게 된다. 또, 세그먼트 번호를 통해 세그먼트 테이블에 접근해 기준점과 한계점을 가지고 오는데, 만약 오프셋이 limit 보다 크다면 예외상황을 발생시켜 메모리 위치에 대한 접근을 봉쇄하게 된다. 이 두가지를 만족한다면 유효한 메모리 접근요청으로 판단해 주소 변환 작업이 이루어진다.
세그먼테이션 기법에서도 페이징 기법과 마찬가지로 보호비트와 유효비트를 둔다. 그리고 특정 세그먼트를 공유해 사용하는 공유 세그먼트 개념을 지원한다.
세그먼트는 의미 단위로 나누어져 있기 때문에 공유와 보안의 측면에서 페이징 기법에 비해 훨씬 효과적이다. 주소 공간의 일부를 공유하거나 특정 주소 공간에 읽기전용 등의 접근 권한 제어를 하고자 할 경우, 이는 어떤 의미 단위로 이루어지지 단순히 크기 단위로 수행되지 않기 때문이다. 예를 들어 페이징 기법에서 동일한 크기로 주소 공간을 나누다 보면 공유하려는 코드와 사유 데이터 영역이 동일 페이지에 공존하는 경우가 발생할 수 있다. 그러나 세그먼테이션 기법에서는 이런 현상이 발생하지 않으므로 공유나 보안처럼 의미있는 단위에 대해 수행하는 업무에서는 페이징 기법보다 세그먼테이션 기법이 장점을 가진다. 단점이라면 크기가 균일하지 않기 때문에 외부조각이 발생하게 되며, 세그먼트를 어느 가용 공간에 할당할 것인지 결정하는 문제가 발생한다. 이는 앞서 말한 연속할당 메모리 관리의 가변분할 방식에서의 문제와 동일한 범주의 문제라 할 수 있다. 최초적합 방식이나 최적적합 방식이 있다.
페이지드 세그먼테이션
세그먼테이션 기법처럼 프로그램을 의미 단위의 세그먼트로 나눈다. 단 세그먼트가 임의의 길이를 가질 수 있는 것이 아니라 반드시 동일한 크기 페이지들의 집합으로 구성되어야 한다. 그리고 물리적 메모리에 적재하는 단위는 페이지 단위로 한다.
즉 페이지드 세그먼테이션 기법에서는 하나의 세그먼트 크기를 페이지 크기의 배수가 되도록 함으로써 세그먼테이션 기법에서 발생하는 외부조각의 문제점을 해결하며, 동시에 세그먼트 단위로 프로세스 간의 공유나 프로세스 내의 접근 권한 보호가 이루어지도록 함으로써 페이징 기법의 약점을 해소한다.
페이지드 세그먼테이션 기법에서는 주소 변환을 위해 외부의 세그먼트 테이블과 내부의 페이지 테이블, 이렇게 두 단계의 테이블을 이용한다. 하나의 세그먼트가 여러 개의 페이지로 구성되므로 각 세그먼트마다 페이지 테이블을 가지게 되는데, 2단계 페이지 테이블과 유사한 구조이다.
<세그먼트 번호, 오프셋>으로 구성된 논리적 주소에서 세그먼트 번호를 통해 세그먼트 테이블에 접근한다. 이 항목에는 세그먼트 길이와 세그먼트의 페이지 테이블 시작 주소가 들어있다. 이 때 세그먼트 길이값과 오프셋값 비교해서 트랩처리를 해줄지 말지 확인한다. 이후 오프셋 값을 상위 하위 비트로 나누어 상위 비트는 그 세그먼트 내에서 페이지 번호로 사용하고 하위 비트는 페이지 내에서의 변위로 사용하게 된다. 세그먼트 테이블의 항목을 통해 해당 페이지 테이블의 시작 위치를 얻었으므로, 그 위치에서 페이지 번호만큼 떨어진 페이지 테이블 항목으로부터 물리적 메모리의 페이지 프레임 위치를 얻게 된다. 그 위치에서 오프셋의 하위 비트값을 더해서 물리적 메모리 주소를 구한다.
'공부 기록들' 카테고리의 다른 글
디스크 관리 (0) | 2020.10.25 |
---|---|
가상 메모리 (0) | 2020.10.25 |
프로세스 관리 (0) | 2020.10.23 |
CPU 스케줄링 (0) | 2020.10.23 |
앞으로 (0) | 2020.06.26 |