Table of Contents
메모리: CPU의 작업 공간, 프로세스가 실행될 때 올라가는 공간
메모리 관리 개요
메모리 관리의 복잡성
- 메모리는 1Byte 크기로 나뉘어 각 영역을 메모리 주소로 구분한다.
- 메모리 주소는 보통 0번지부터 시작한다.
- CPU는 메모리에 있는 내용을 가져오거나 작업 결과를 메모리에 저장하기 위해 메모리 주소 레지스터(MAR)를 사용한다.
- (MAR에 필요한 메모리 주소를 넣으면 데이터를 메모리에서 가져오거나 메모리에 데이터를 옮길 수 있다)
- 여러 작업을 동시에 처리(시분할 시스템)할 때 메모리 관리는 메모리 관리 시스템(MMS)이 담당한다.
메모리 관리의 이중성
- 메모리 관리의 이중성이란 프로세스 입장에서는 메모리를 독차지하려고 하고, 메모리 관리자 입장에서는 되도록 관리를 효율적으로 하고 싶어하는 것을 말한다.
- 프로세스가 작업하는 도중에 할당된 공간이 부족하면 메모리 관리자는 새로운 공간을 확보하기 위해 옆의 프로세스를 밀어내거나 더 큰 공간으로 해당 프로세스를 옮겨준다. 이처럼 매번 작업 공간을 키웠다 줄였다 하는 것은 매우 복잡한 일이다.
메모리 관리자의 역할
- 메모리 관리는 메모리 관리자가 담당한다.
- 메모리 관리자는 정확히 말해 메모리 관리 유닛(MMU)이라는 하드웨어이다.
- 메모리 관리자의 작업은 가져오기, 배치, 재배치이다
- 가져오기(fetch)
- 사용자가 요청시 메모리 관리자가 작업을 수행
- 프로세스와 데이터를 메모리로 가져오는 작업
- 어떤 경우는 데이터를 일부만 가져오기도 하고, 미리 가져오기(prefetch)도 한다
- 배치(placement)
- 가져온 프로세스와 데이터를 메모리의 어떤 부분에 올려놓을지 결정하는 작업
- 배치 작업 전에 메모리를 어떤 크기로 자를 것인지가 매우 중요
- 페이징: 메모리를 같은 크기로 자르는 것
- 세그먼테이션: 프로세스의 크기에 맞게 자르는 것
- 재배치(replacement)
- 새로운 프로세스를 가져올 때, 메모리가 꽉 찬 경우 메모리에 있는 오래된 프로세스를 스왑 아웃
- 페이지 교체 알고리즘
메모리 주소
- 메모리에 접근할 때는 주소를 이용한다.
- 메모리 주소는 절대 주소와 상대 주소로 나뉜다.
메모리 영역의 구분
메모리는 크게 운영체제가 올라가는 영역과 사용자의 응용 프로그램이 올라가는 영역으로 나뉜다. 운영체제는 중요한 역할을 하기 때문에 사용자가 운영체제를 침범하지 못하도록 분리하는 것이 중요하다. 운영체제가 0~359번지를 사용하면 사용자는 360번지 부터 사용해야 한다. 사용자 영역이 운영체제 영역으로 침범하는 것을 막으려면 하드웨어의 도움이 필요한데, 이는 CPU 내에 있는 경계 레지스터가 담당한다. 경계 레지스터는 운영체제 영역과 사용자 영역 경계 지점의 주소를 가진 레지스터이다.
절대 주소와 상대 주소
- 절대 주소
- 실제 물리 주소
- 메모리 관리자 입장에서 바라본 주소
- MAR이 사용하는 주소
- 상대 주소(논리주소)
- 메모리 중 사용자 영역의 시작 위치를 0번지로 고정하고 사용하는 지정 방식
- 컴파일 방식을 사용하는 프로그램의 경우 컴파일 시점에 변수가 메모리 어느 위치에 올라갈지 미리 알 수 없다
- 그래서 우선 0번지로 고정하고 실제 물리 주소에 맞게 매핑한다
- 사용자 프로세스 입장에서 바라본 주소
32bit CPU와 64bit CPU의 차이
CPU의 비트는 한 번에 다룰 수 있는 데이터의 최대 크기
CPU 내부 부품은 모두 이 비트를 기준으로 제작된다.
32bit CPU 내의 레지스터 크기는 전부 32bit
산술 논리 연산장치도 32bit를 처리할 수 있도록 설계된다.
데이터를 전송하는 각종 버스의 크기(대역폭)도 32bit -> 한 번에 옮겨지는 데이터의 크기는 32bit
CPU의 비트는 메모리 주소 공간의 크기와도 연관이 있다. 32bit CPU의 경우 메모리 주소를 지정하는 레지스터(MAR)의 크기가 32bit이므로 표현할 수 있는 메모리 주소의 범위가 0 ~ 2의 32승 - 1이다. 메모리 공간 하나의 크기가 1Byte이므로 총 크기는 4GB이다. 즉 32bit CPU 컴퓨터는 최대 4GB의 메모리를 가질 수 있다. (64bit CPU는 16,777,216TB)
32비트 MAR은 1Byte 크기의 메모리 단위를 2의 32승개 구분할 수 있다 -> 2의 32승 * 1Byte -> 4 * 2의 30승 * 1Byte -> 4 * 1GB -> 4GB
메모리 오버레이
과거에는 메모리가 값비싼 저장장치라 큰 메모리를 사용할 수 없었다. 이 때문에 큰 프로그램을 어떻게 실행시킬지에 대한 고민이 있었다. 예를 들어 1MB 메모리의 컴퓨터에 10MB 크기의 프로그램을 실행하려면 어떻게 해야 할까?
방법은 간단하다. 프로그램의 크기가 물리 메모리에 남은 용량보다 더 클 때 전체 프로그램을 메모리에 가져오는 대신 적당한 크기로 잘라서 가져오는 기법을 메모리 오버레이(momory overlay)라고 한다. 예를 들어 한글 문서 편집기에는 기본 문서 편집 기능 외에 맞춤법 검사, 그림판 등의 기능이 있다. 이러한 기능은 각각 모듈 형태로 분리되어 있다가 프로그램이 실행되면 필요한 모듈만 메모리에 올라와 실행된다. 이렇게 하면 프로그램 전체를 메모리에 올려놓고 실행하는 것보다 속도가 느리지만 용량이 큰 프로그램도 실행 할 수 있다.
메모리 오버레이에서 어떤 모듈을 가져오고 내보낼지는 CPU 레지스터 중 하나인 프로그램 카운터(PC)가 결정한다. 프로그램 카운터는 앞으로 실행할 명령어의 위치를 가리키는 레지스터로, 해당 모듈이 메모리에 없으면 메모리 관리자에게 요청해 메모리로 가져오게 한다.
스왑
메모리 오버레이가 언제나 가능한 건 아니다. 남은 모듈을 임시 보관할 수 있는 저장공간이 있어야 한다. 예를 들어 1MB 메모리에 10MB 프로그램을 실행하려면 최소한 9MB 만큼 크기의 임시 저장공간이 필요한데 이러한 공간을 스왑(swap) 영역이라고 한다.
이처럼 물리 메모리의 저장 공간이 부족해서 남은 프로세스를 저장하는 공간을 스왑 영역이라고 하며 스왑 영역에서 메모리로 데이터를 가져오는 작업을 스왑인, 스왑 영역으로 데이터를 내보내는 작업을 스왑아웃 이라고 한다.
스왑 영역은 메모리 관리자가 관리한다. 원래 하드디스크 같은 저장장치는 저장장치 관리자가 관리하지만, 스왑 영역은 메모리에 있다가 스왑아웃된 데이터가 머무는 곳이기 때문에 메모리 관리자가 관리한다.
하드디스크의 일부를 스왑 영역으로 사용함으로써 사용자는 실제 메모리의 크기와 스왑 영역의 크기를 합쳐서 전체 메모리로 인식하고 사용할 수 있다.
메모리 분할
한 번에 여러 프로세스를 실행하는 경우 메모리 관리가 더욱 복잡해진다. 가장 큰 문제는 프로세스들의 크기가 달라 메모리를 어떻게 나누어 사용하는가이다.
- 가변 분할 방식
- 프로세스의 크기에 따라 메모리를 나누는 것
- 하나의 프로세스끼리 연속된 공간에 배치해야 한다
- 연속 메모리 할당이라고도 한다
- 메모리 관리가 복잡하다
- (군데군데 남은 공간보다 큰 프로세스가 들어오면 빈공간을 하나로 합치기 위해 기존 프로세스의 자리 이동이 발생)
- (빈공간이 발생하는 것을 외부 단편화라고 하고, 합치는 것을 조각 모음(defragmentation)이라고 한다)
- (가변 분할 배치는 선처리, 조각 모음은 후처리인 것이다)
- (이런 조각 모음은 하드디스크에 발생, 저장-삭제 많이 일어나면 군데군데 빈 공간 발생 -> 성능 저하 -> 조각 모음 필요)
- 장점: 프로세스를 한 덩어리로 관리 가능
- 단점: 빈 공간의 관리가 어려움 (연속된 배치를 위해 조각 모음이 자주 발생하고 결과적으로 기존의 조각들은 계속해서 위치가 이동함)
- 고정 분할 방식
- 프로세스의 크기와 상관없이 메모리를 같은 크기로 나누는 것
- 같은 프로세스들이 분산되어 배치된다
- 비연속 메모리 할당이라고도 한다
- 관리가 수월하다
- 고정 크기보다 작은 프로세스가 들어오면 군데군데 빈 공간 발생(고정 크기 내 다른 프로세스와 공간 공유x) -> 메모리 낭비
- (고정 분할에서 빈 공간이 생기는 것을 내부 단편화라고 함)
- 내부 단편화는 조각 모음도 안되고, 남은 공간을 다른 프로세스에 배정해 주지도 못한다
- 장점: 메모리 관리가 편리
- 단점: 프로세스가 분할되어 처리됨, 메모리 낭비 발생
현대 운영체제에서 메모리 관리는 기본적으로 고정 분할 방식을 사용하면서 일부분 가변 분할 방식을 혼합한다.
가상 메모리 기술에 기반한 메모리 관리
가상 메모리 기술: 물리 메모리의 크기와 상관없이 프로세스를 실행할 수 있도록 지원하는 기술
(원래는 프로그램 크기에 대한 고민이 필요했지만 이제는 그런 걱정 없이 프로그램 개발이 가능해졌다)
현대 메모리 관리의 가장 큰 특징은 물리 메모리의 크기와 프로세스가 올라갈 메모리의 위치를 신경쓰지 않고 프로그래밍하도록 지원한다는 것이다. 이러한 메모리 시스템을 가상 메모리라고 부른다.
가상 메모리는 물리 메모리의 크기와 스왑 영역을 합한 크기이다.
가상 메모리 시스템에서는 물리 메모리의 내용 중 일부를 하드디스크의 일부 공간, 즉 스왑 영역으로 옮긴다. 스왑 영역은 하드디스크에 존재하지만 메모리 관리자가 관리하는 영역이다. 즉 물리 메모리가 꽉 찼을 떄, 일부 프로세스를 스왑 영역으로 보내고, 몇 개의 프로세스가 작업을 마치면 스왑 영역에 있는 프로세스를 메모리에 가져온다.
가상 메모리 시스템에서 가변 분할 방식을 세그멘테이션(segmentation), 고정 분할 방식을 페이징(paging)이라고 한다.
메모리를 관리할 때는 매핑 테이블을 작성하여 관리한다. 가상 메모리 시스템에서 가상 주소는 실제로 물리 주소나 스왑 영역 중 한 곳을 가리키며, 메모리 관리자는 가상 주소와 물리 주소를 일대일 매핑 테이블로 관리한다. 메모리 매핑 테이블을 이용하면 가상 주소가 물리 메모리의 어느 위치에 있는지 알 수 있다.
페이징도 위의 세그멘테이션과 똑같은 방식으로 적용된다. 페이징 기법에서 사용하는 매핑 테이블은 페이지 매핑 테이블, 세그먼테이션 기법에서 사용하는 매핑 테이블은 세그먼테이션 매핑 테이블이라고 부른다.
가상 주소
- 사용자가 어떤 부분이 메모리에 올라와 있는지, 스왑 영역에 있는지 고민해야 한다면 사용하기 굉장히 불편할 것이다. 이런 문제를 해결해주는 것이 가상 주소
- 프로세스는 가상 주소를 할당 받는다. 사용자 눈에는 마치 가상 메모리라는 메모리가 있고 그 위에 프로세스가 올라온 것 같은 경험을 한다. 그러나 실제로 가상 메모리라는 것은 없고, 논리적인 개념일 뿐이다. 사용자가 어떤 프로세스에 접근을 하면 메모리 관리자는 매핑 테이블을 통해 물리 주소로 매핑해준다. 물리 주소를 보면 실제로 요청된 프로세스가 물리 메모리에 있을 수도 있고, 스왑 영역에 있을 수도 있다. 스왑 영역에 있다면 페이지 교체 알고리즘을 통해 스왑 영역에 있는 프로세스를 스왑인하여 물리 메모리에 올리고 그 주소를 매핑 테이블에 업데이트 한 후, 사용자에게 돌려준다.
페이징 기법
사용자 입장에서 프로세스는 가상 메모리(가상 주소 공간)에 올라간다. 위에서 프로세스가 메모리에 올라갈 때 고정 분할 방식과 가변 분할 방식이 있다고 했다. 가상 메모리는 같은 개념을 페이징, 세그멘테이션이라고 한다.
가상 메모리에 프로세스를 올릴 때 메모리를 할당하는 방식
페이징: 프로세스 크기에 상관없이 일정한 크기로 메모리를 할당
세그멘테이션: 프로세스 크기에 비례해 메모리를 할당
페이지와 프레임의 크기는 같다
가상 주소를 물리 주소로 변경하는 방법
페이지 테이블 관리
페이지 테이블 매핑 방식
세그먼테이션 기법
가상 주소를 물리 주소로 변경하는 방법
세그먼테이션-페이징 혼용 기법
가상 주소를 물리 주소로 변경하는 방법
페이지 교체 알고리즘
FIFO 페이지 교체
가장 간단한 페이지 교체 알고리즘으로 FIFO(first-in first-out)의 흐름을 가진다. 즉, 먼저 물리 메모리에 들어온 페이지 순서대로 페이지 교체 시점에 먼저 나가게 된다는 것이다.
-
장점
- 이해하기도 쉽고, 프로그램하기도 쉽다.
-
단점
- 오래된 페이지가 항상 불필요하지 않은 정보를 포함하지 않을 수 있다(초기 변수 등)
- 처음부터 활발하게 사용되는 페이지를 교체해서 페이지 부재율을 높이는 부작용을 초래할 수 있다.
Belady의 모순
: 페이지를 저장할 수 있는 페이지 프레임의 갯수를 늘려도 되려 페이지 부재가 더 많이 발생하는 모순이 존재한다.
LRU 페이지 교체(LRU Page Replacement)
LRU: Least-Recently-Used
최적 알고리즘의 근사 알고리즘으로, 가장 오랫동안 사용되지 않은 페이지를 선택하여 교체한다.
- 특징
- 대체적으로
FIFO 알고리즘
보다 우수하고,OPT알고리즘
보다는 그렇지 못한 모습을 보인다.
- 대체적으로
LFU 페이지 교체(LFU Page Replacement)
LFU: Least Frequently Used
참조 횟수가 가장 적은 페이지를 교체하는 방법이다. 활발하게 사용되는 페이지는 참조 횟수가 많아질 거라는 가정에서 만들어진 알고리즘이다.
- 특징
- 어떤 프로세스가 특정 페이지를 집중적으로 사용하다, 다른 기능을 사용하게되면 더 이상 사용하지 않아도 계속 메모리에 머물게 되어 초기 가정에 어긋나는 시점이 발생할 수 있다
- 최적(OPT) 페이지 교체를 제대로 근사하지 못하기 때문에, 잘 쓰이지 않는다.
캐시의 지역성
캐시의 지역성 원리
캐시 메모리는 속도가 빠른 장치와 느린 장치간의 속도차에 따른 병목 현상을 줄이기 위한 범용 메모리이다. 이러한 역할을 수행하기 위해서는 CPU 가 어떤 데이터를 원할 것인가를 어느 정도 예측할 수 있어야 한다. 캐시의 성능은 작은 용량의 캐시 메모리에 CPU 가 이후에 참조할, 쓸모 있는 정보가 어느 정도 들어있느냐에 따라 좌우되기 때문이다.
이 때 적중율(Hit rate)
을 극대화 시키기 위해 데이터 지역성(Locality)의 원리
를 사용한다. 지역성의 전제조건으로 프로그램은 모든 코드나 데이터를 균등하게 Access 하지 않는다는 특성을 기본으로 한다. 즉, Locality
란 기억 장치 내의 정보를 균일하게 Access 하는 것이 아닌 어느 한 순간에 특정 부분을 집중적으로 참조하는 특성인 것이다.
이 데이터 지역성은 대표적으로 시간 지역성(Temporal Locality)과 공간 지역성(Spatial Locality)으로 나뉜다.
- 시간 지역성 : 최근에 참조된 주소의 내용은 곧 다음에 다시 참조되는 특성.
- 공간 지역성 : 대부분의 실제 프로그램이 참조된 주소와 인접한 주소의 내용이 다시 참조되는 특성
Caching line
언급했듯이 캐시(cache)는 프로세서 가까이에 위치하면서 빈번하게 사용되는 데이터를 놔두는 장소이다. 하지만 캐시가 아무리 가까이 있더라도 찾고자 하는 데이터가 어느 곳에 저장되어 있는지 몰라 모든 데이터를 순회해야 한다면 시간이 오래 걸리게 된다. 즉, 캐시에 목적 데이터가 저장되어 있다면 바로 접근하여 출력할 수 있어야 캐시가 의미 있어진다는 것이다.
그렇기 때문에 캐시에 데이터를 저장할 때 특정 자료구조를 사용하여 묶음
으로 저장하게 되는데 이를 캐싱 라인 이라고 한다. 프로세스는 다양한 주소에 있는 데이터를 사용하므로 빈번하게 사용하는 데이터의 주소 또한 흩어져 있다. 따라서 캐시에 저장하는 데이터에는 데이터의 메모리 주소 등을 기록해 둔 태그를 달아놓을 필요가 있다. 이러한 태그들의 묶음을 캐싱 라인이라고 하고 메모리로부터 가져올 때도 캐싱 라인을 기준으로 가져온다.
종류로는 대표적으로 세 가지 방식이 존재한다.
- Full Associative
- Set Associative
- Direct Map