들어가기 전에
학교 수업 때 배운걸 다시 정리해서 쓴 글입니다.
오타 및 잘못된 부분 지적은 언제나 환영입니다!
주소체계는 8bit, 페이지 테이블 항목(Page Table Entry)는 4byte로 예시를 만들었습니다.
주소 변환이 필요한 이유
프로세스가 메모리에 할당되는 과정에서 연속된 공간을 할당받지 못하거나
문맥 교환을 통해 이전과는 다른 메모리 공간을 할당받을 수 있다.
이런 상황에서도 프로세스의 논리적 주소를 기반으로 물리 메모리에 매칭시키게 해야 한다.
이렇게 주소 변환 기법을 통해 프로세스는 물리 메모리에 자신만의 독립된 공간이 있다는 환상을 가진다.
메모리 관련 용어
동적 로딩 : 프로세스를 실행할 땐, 모든 정보가 메모리에 올라가지 않고, 필요한 부분만 올라가게 하는 기법\
동적 링킹 : 프로그램에 포함된 라이브러리들을 필요할 때만 가져올 수 있도록 분리.
이 작업을 통해 실행 파일의 크기를 줄일 수 있다.
스와핑 : 프로세스 실행에 필요한 물리 메모리 공간이 부족할 때, blocking 상태의 다른 프로세스를 디스크로 스왑 아웃시키는 기법
가상화 전략
MMU기법 : CPU가 프로세스의 논리적 주소를 참조할 때, 기준 레지스터를 더해 접근하려는 물리 메모리의 시작점을 알려준다. 이 과정에서, 한계 레지스터의 값을 초과하는 접근이면 trap이 발생하고, 해당 프로세스는 종료된다.
(MMU : Memory Management Unit)
유효 비트
- 페이지 테이블 관점 : 페이지가 메모리 적재 유무 확인
- TLB 관점 : 해당 페이지를 가진 프로세스의 문맥 교환 유무 확인
보호 비트 : 리눅스의 rwx 권한 처럼 해당 페이지에 대해 읽기, 쓰기 권한 부여
세그먼테이션
프로세스 주소 공간(스택, 데이터, 코드 등)같이 의미있는 공간들을 하나의 세그먼트로 구성.
세그먼트 별로 크기가 다르기 때문에 세그먼트들이 메모리에 배치되는 과정에서 외부 단편화가 발생할 수 있다.
주소 표현이 <세그먼트 번호, offset> 쌍으로 이루어져 있다.
세그먼트 테이블은 각 영역의 기준점과 한계점에 대한 정보를 가지고 있다.
각 지점들에 대한 정보는 레지스터를 통해 관리한다.
만약, 세그먼트 범위 외의 공간에 접근하면 그 유명한 Seg Fault를 반환한다.
세그먼테이션 기법에서 논리적 주소를 물리적 주소로 변환하는 과정이다.
프로그램 주소 공간은 스택, 힙, 코드 3가지로 보고 있기 때문에
set bit를 2bit로 주고 나머지는 offset bit로 지정했다.
주소 표현을 해석하면
1번 세그먼트에서 48번 offset에 접근하라는 뜻이다.
페이징
프레임 : 물리 메모리를 일정한 크기로 나눈 단위
프로세스 역시 페이지란 단위로 나누며, 프레임과 같은 크기를 가짐
페이지와 프레임의 크기는 같기 때문에, 빈 프레임이 있다면 그곳에 페이지를 배치할 수 있다.
VPN(Virtual Page Number) : 가상 페이지 번호
PFN(Physical Frame Number) : 물리 메모리 프레임 번호
페이지 테이블은, <VPN, PFN> 쌍을 가진다.
테이블에 대한 표현은 이 글처럼 번호로 표현한 경우도 있고, 주소로 표현한 경우도 있는데 둘 다 의미는 같다.
페이징 기법에서 논리적 주소를 물리적 주소로 변환하는 과정이다.
5번째 VPN이 가리키는 PFN의 16번째 offset 위치에 접근을 한다.
페이징 기법 문제
32bit 컴퓨터 기준, 페이지의 크기는 보통 4KB로 2^12이다.
이 12bit는 offset으로 사용되고, 나머지 20bit는 식별 비트로 사용된다.(대충 100만 byte)
페이지 테이블의 각 항목은 4byte정도 되니, 페이지 테이블의 총 크기는 4MB가 된다.
문제는 각 프로세스는 하나의 페이지 테이블을 가지기 때문에 프로세스 10개만 돌아가도 40MB의 메모리 공간을 차지하고, 실행되는 프로세스가 많을 수록, 메모리 낭비가 심하다.
이 문제를 해결하기 위해 여러 방법들이 생겼다.
역페이징
페이징이 논리 주소를 통해 물리 메모리의 주소를 찾는 것이라면
역페이징은 물리 메모리 주소가 가리키는 논리 주소를 찾는 것이다.
이러면, 프로세스마다 테이블을 만들 필요 없이 운영체제만 테이블을 하나 만들어 관리하면 된다.
프레임에 하나의 페이지 테이블 항목을 할당해 크기가 고정된 테이블을 갖는다.
테이블은 <프로세스 ID, 페이지 번호> 쌍을 가지며
일치하는 테이블 index가 메모리 프레임 번호가 된다.
단, 이 작업은 선형으로 탐색하면 매우 느리기 때문에 병렬 연산을 해주는 레지스터를 지원한다.
8bit 크기의 논리적 주소를 예시 프로세스 ID를 이용해 물리적 주소로 변환하는 과정이다.
먼저, PID 4000와 VPN 2에 대한 쌍을 역페이징 테이블에서 찾는다.
이 때 해당 쌍이 존재하는 곳은 3번째 인덱스이며
물리 메모리의 3번째 프레임의 32번째 offset에 접근한다.
세그먼테이션-페이징
메모리를 프레임 단위로 나누면서, 그 중 비슷한 의미를 가지는 곳끼리 세그먼트로 묶어서 관리한다.
세그먼트 내부에서 자유롭게 페이지 교체가 가능하지만
여전히 세그먼트란 불규칙적인 크기를 메모리에 배치하기 때문에 외부 단편화 문제는 있다.
기존과는 달리 베이스 레지스터는 세그먼트의 시작 주소가 아닌 해당 세그먼트의 페이지 테이블의 시작 주소를 나타낸다.
마찬가지로 한계 레지스터는 페이지 테이블의 끝을 가리킨다.
세그먼트 개수 만큼 페이징 테이블을 가지며, 세그먼트 페이지가 많을 수록 페이징 테이블의 크기가 작아진다.
변환 과정은 세그먼트 bit를 보고 해당 세그먼트 페이징 테이블로 이동한다. 그 후, 페이징 테이블과 VPN bit를 매칭해 테이블이 가리키는 프레임으로 이동한다.
8bit 크기의 주소 공간을 예시로 보자.
여기서도 프로세스 주소 공간은 스택, 데이터, 코드 3가지로 볼 것이기 때문에 세그먼트 길이는 3이다.
주소를 해석하면, 1번 세그먼트의 1번 VPN이 있는 메모리 프레임의 16번째 offset에 접근하겠다는 뜻이다.
멀티 레벨 페이징
세그먼테이션-페이징의 단편화 문제를 해결하기 위해 생겼다.
페이징 테이블을 여러 단계를 두고 메모리 프레임에 접근한다.
즉, 페이지 테이블을 트리 구조로 표현한다.
(인텔 x86에선 이 기법을 사용한다.)
이렇게 외부, 내부 페이지 테이블로 나뉘는데, 외부 페이지 테이블들은 다른 페이지 테이블로 연결해주는 페이지 디렉토리(PDE, Page Directory Entries) 역할을 한다.
페이지 테이블 트리의 leaf node에 속하는 테이블들이 VPN과 PFN을 매치하는 역할을 한다.
8bit 크기의 주소 공간을 예시로 보자.
전체 테이블은 4bit로 표현되며, 전체 테이블은 16개의 항목을 갖고 있다.
여기에 페이지 디렉토리 비트를 2bit로 정해주면, 페이지 테이블은 4개씩 분할된다.
주소 공간을 해석하면 페이지 디렉토리 0번째 항목이 가리키는 페이지 테이블에서 3번째 항목이 가리키는 메모리 프레임의 0번째 주소에 접근하라는 뜻이다.
하지만, 메모리 접근 속도는 느린 편에 속하기 때문에, 단계가 많아질 수록, 메모리에 접근하는 횟수가 많아진다.
즉, 페이징 테이블 구성 크기는 줄지만, 속도는 감소한다.
다행히도, 이 메모리 접근 문제를 해결할 수 있는 방법이 있다.
TLB(Translation Lookaside Buffer)
변환-색인 버퍼, 고속 하드웨어 캐시로, 페이지 테이블 접근 과정에서 생기는 메모리 오버헤드 해결.
크기가 작기 때문에 자주 참조되는 페이지에 대한 정보만 갖는다.
VPN을 TLB에서 찾을 수 없다면, TLB 미스 혹은 캐시 미스라고 한다.
메모리에 접근해 페이지 테이블 항목(PTE)를 TLB에 등록한 다음 명령어를 재실행 한다.
하지만, 해당 PTE가 디스크로 스왑 아웃돼 유효 비트가 0인 상태라면 페이지 폴트가 발생한다.
이 땐, 인터럽트가 발생해 운영체제로 제어권이 넘어간다.
페이지 폴트 핸들러는 디스크에 해당 페이지에 대한 I/O 요청을 하면서 프로세스는 block 상태가 된다.
디스크는 해당 페이지가 있는 block을 DMA를 통해 메모리에 올리고, 유효 비트를 1로 한다.
TLB에도 이 작업을 해준 뒤, 제어권을 프로세스에게 돌려주면서 실패한 명령어를 다시 실행하게 한다.
TLB에서의 문맥 교환
page fault 발생시, 프로세스는 blocking 상태가 되고, 그 자리를 다른 프로세스가 차지한다.
새로 자원을 할당 받은 프로세스는 기존의 TLB가 필요 없게 돼 새로 TLB를 등록해야 한다.
이렇게 되면 문맥 교환이 발생할 때마다 TLB를 다시 설정해야 한다.
따라서 기존 TLB 테이블에 ASID(Address space identifier) 정보를 추가한다.
ASID란 PID에 고유 식별자를 지정한 형태이다.
PID를 그대로 쓰지 않은 이유는, PID의 표현 범위는 매우 넓기 때문에 작은 범위로 제한해야 하기 때문이다.
ASID를 통해 프로세스 별로 올바른 주소 변환을 할 수 있게 된다.
문맥 전환 시, 운영체제는 새로운 ASID 값을 레지스터에 등록시킨다.
'학교 > os' 카테고리의 다른 글
파일 시스템 (0) | 2022.07.10 |
---|---|
스레드 (0) | 2022.07.10 |
문맥 교환(context switching) (0) | 2022.06.27 |
프로세스의 생성과 통신 (0) | 2022.06.26 |
프로세스 구조 (0) | 2022.06.26 |