패스트캠퍼스 컴퓨터 공학자 따라잡기 온라인 완주반
운영체제(이준희 님) 파트를 수강하며 공부한 내용을 정리한 자료입니다.
배너: godori님이 만드신 배너 메이커 활용
가상 메모리 개념
가상 메모리 (Virtual Memory System)
- 요즘 통상적으로 컴퓨터의 메모리는 8GB 혹은 16GB이다.
- 리눅스의 경우 하나의 프로세스가 4GB인데, 실제로 각각의 프로세스에 이만큼의 메모리를 할당하기에는 실제 메모리 크기에 한계가 있다.
- 그런데 프로세스를 실행하기 위해서 코드는 반드시 메모리에 있어야 한다.
가상 메모리:
메모리가 실제 메모리보다 많아 보이게 하는 기술
- 실제 사용하는 메모리는 그렇게 크지 않다는 점에 착안해서 고안된 기술
- 프로세스 간 공간 분리로, 프로세스 이슈가 전체 시스템에 영향을 주지 않을 수 있음
리눅스의 경우 한 프로세스 당 4GB의 가상 메모리를 가지게 되는데, 0~3GB 까지는 사용자 영역, 3~4GB의 영역은 커널 영역이다.
프로세스는 총 4GB의 메모리를 모두 사용하는 것은 아니고, 이 중 일부만을 실제 물리 메모리에 올려놓게 되는 것이다.
하나의 프로세스만 실행 가능한 시스템(배치 처리 시스템 등)의 경우 가상 메모리를 필요로 하지 않는다.
- 프로그램을 메모리로 로드(load)
- 프로세스 실행
- 프로세스 종료(메모리 해제)
하지만 여러 프로세스를 동시에 실행하는 시스템의 경우 아래와 같은 이유로 가상 메모리를 필요로 하게 된다.
- 메모리 용량 부족 이슈
- 프로세스 메모리 영역 간 침범 이슈
가상 메모리의 기본 아이디어
- 프로세스는 가상 주소를 사용하고, 실제 해당 주소에서 데이터를 읽고 쓸 때만 물리 주소로 바꿔주면 된다.
- virtual address (가상 주소): 프로세스가 참조하는 주소 (0~4GB)
- physical address (물리 주소): 실제 메모리 주소
CPU가 특정 프로세스의 어떤 공간을 참조할 때는 우선 가상 주소를 먼저 참조하고, 가상 주소에 해당하는 실제 물리 주소를 참조하게 된다.
가상 주소를 참조할 때마다 매번 이를 물리 주소로 변환을 하게 되니까 이 시간을 짧게 하려고 MMU라는 하드웨어 칩의 지원을 받는다. MMU는 가상 주소를 물리 주소로 빠르게 변환해주는 역할을 한다.
MMU (Memory Management Unit):
CPU에 코드 실행 시, 가상 주소 메모리 접근이 필요할 때 해당 주소를 물리 주소값으로 변환해주는 하드웨어 장치.
그림 1. 가상 메모리와 MMU의 관계
- CPU는 가상 메모리 주소를 다루고, 실제 해당 주소 접근 시 MMU 하드웨어 장치를 통해 물리 메모리에 접근한다.
- 하드웨어 장치를 이용해야 주소 변환이 빠르기 때문에 MMU라는 별도의 장치를 두고 있는 것이다.
페이징 시스템 (Paging System)
페이징 개념
하나의 프로세스에서 특정 시간 동안 쓰는 메모리 영역은 4GB 중 아주 일부분이기 때문에 일부분만 실제 물리 메모리에 올려놓고 쓰자는 것이 가상 메모리의 컨셉이다.
그럼 어느 정도의 사이즈만큼 메모리에 올릴 지에 대한 결정이 필요하다(100MB? 1GB? 등).
이를 페이지(page)라는 단위로 다루겠다고 하는 것이 바로 페이징 시스템이다.
페이징(paging):
- 크기가 동일한 페이지 단위로 가상 주소 공간과 이에 매칭되는 물리 주소 공간을 관리
- 하드웨어 지원이 필요
- 예) Intel x86 시스템(32bit)에서는 4KB, 2MB, 1GB 지원
- 리눅스에서는 4KB로 paging
- 페이지 번호를 기반으로 가상 주소와 물리 주소의 매핑 정보를 기록하고 사용한다.
- 리눅스의 경우 4GB의 가상 메모리를 4KB 단위로 쪼개서 페이징하고 페이지 번호를 붙임
- 페이지 단위로 물리 메모리에 넣고, 해당 데이터를 찾을 때에도 페이지 번호를 기반으로 주소를 찾게 된다.
그림 2. 페이징 시스템 예시 (리눅스)
- 프로세스(4GB)의 PCB(Process Control Block)에 Page Table 구조체를 가리키는 주소가 들어 있음
- Page Table에는 가상 주소와 물리 주소 간 매핑 정보가 있음
CPU가 특정 가상 주소를 참조하게 되면, 그 가상 주소가 몇 페이지인 지를 알 수 있고, 이를 통해 Page Table에서 해당 페이지의 실제 물리 메모리 주소를 알아낼 수 있다.
페이징 시스템 구조
- page 또는 page frame: 고정된 크기의 block (4KB)
가상 주소 v = (p, d)
- p: 가상 메모리 페이지
- d: p 안에서 참조하는 위치
- 페이지 크기가 4KB인 경우
- 가상 주소의 0비트에서 11비트가 변위(d)를 나타내고
- 12비트 이상이 페이지 번호가 될 수 있음
그림 3. 가상 주소의 구조
cf) 프로세스가 4GB를 사용하는 이유 - 32bit 시스템에서 2의 32 거듭제곱이 4GB (결국 이 사이즈도 bit와 연결되는 것)
페이지 테이블 (Page Table)
page table
- 가상 주소에 있는 페이지 번호와 해당 페이지의 첫 물리 주소 정보를 매핑한 표
- 가상 주소 v = (p, d)라면
- p: 페이지 번호
- d: 페이지 처음부터 떨어진 정도 (위치)
- 특정 프로세스에서 특정 가상 주소에 접근하려면
- 해당 프로세스의 page table에 가상 주소가 포함된 page 번호가 있는 지 확인
- page 번호가 있으면 이 page가 매핑된 첫 물리 주소(p')를 알아내고
- p' + d가 실제 물리 주소가 됨
cf) 가상 메모리의 각 페이지가 실제 물리 메모리에 저장되는 주소 순서는 가상 메모리의 페이지 순서와 상관이 없다.
- 예) 가상 메모리의 페이지 1, 페이지 2, 페이지 3이 실제 물리 메모리에서도 같은 순서대로 저장되는 것이 아님
page table에는 페이지 번호, 가상 주소, 물리 주소 외에도 valid-invalid bit
정보가 저장되는데, 이는 해당 페이지가 현재 물리 메모리에 올라가 있는지를 나타낸다 (v - 올라가 있음, i - 올라가 있지 않음).
페이징 시스템과 MMU의 관계
- CPU는 가상 주소 접근 시
- MMU 하드웨어 장치를 통해 물리 메모리 접근
- 프로세스 생성 시 페이지 테이블 정보가 생성된다. (물리 메모리에)
- PCB 등에서 해당 페이지 테이블에 접근이 가능하고, 관련 정보는 물리 메모리에 적재한다.
- 프로세스 구동 시, 해당 페이지 테이블의 base 주소 (시작 주소)가 별도의 레지스터(CR3)에 저장된다.
- CPU가 가상 주소에 접근 시, MMU가 CR3를 통해 페이지 테이블 base 주소에 접근해서 물리 주소를 가져온다.
다중 단계 페이징 시스템과 페이징 시스템의 적용
다중 단계 페이징 시스템 개념
우리가 아주 간단한 프로그램을 만들 경우 그 용량은 겨우 10KB 정도일 때도 있다. 이 경우 0 ~ 3GB의 사용자 영역 중 대부분의 영역은 쓰이지 않을 것이다.
그런데 항상 전체 페이지 테이블 정보를 다 메모리에 올리게 되면 쓸데없이 많은 공간을 낭비할 수 있다.
페이지 정보를 단계를 나누어 생성함으로써 이러한 공간의 낭비를 막을 수 있는데, 이를 다중 단계 페이징 시스템이라 일컫는다.
- 32bit 시스템에서 4KB 페이지를 위한 페이징 시스템은
- 하위 12bit는 오프셋(d)
- 상위 20bit가 페이징 번호(p)이므로 2의 20 거듭제곱(1048576) 개의 페이지 정보가 필요하다
- 페이징 정보를 단계를 나누어 생성하게 되면
- 필요없는 페이지 정보는 생성하지 않으면 메모리 공간을 절약할 수 있다.
- 데이터가 있는 영역에 대해서만 각 페이지 디렉토리 별로 페이지 테이블을 따로 만든다.
그림 4. 다중 단계 페이징 시스템
- 다중 단계 페이징 시스템에서는 페이지 번호를 나타내는 bit를 구분해서 단계를 나눈다 (리눅스는 3단계, 최근에는 더 복잡하게 4단계로 나눠서 처리를 하는 경우도 있다고 함)
- 이 경우 CR3 레지스터는 페이지 디렉토리의 맨 앞을 가리킴
- 각각의 페이지 디렉토리는 페이지 디렉토리에 해당하는 페이지 테이블 시작 주소를 가리킴
- 페이지 테이블에서 해당 페이지 정보를 찾아서 OFFSET 정보와 함께 활용해, 해당하는 물리 주소를 가지고 오게 됨
MMU와 TLB
그림 5. MMU와 메모리
- MMU가 물리 주소를 확인하기 위해 메모리를 갔다 와야 함
- 메모리에 접근하는 시간은 CPU 안에서 레지스터를 처리하는 시간에 비하면 200배 정도 느림
이 문제를 해결하기 위해 TLB라는 별도의 하드웨어 장치의 지원을 받는다.
그림 6. MMU와 TLB
- TLB (Translation Lookaside Buffer): 최근 페이지 정보 캐쉬
- TLB를 사용하는 경우, 가상 주소와 대응되는 물리 주소는 한 번 변환되면 TLB에 저장되어 그 다음부터는 MMU가 page table에 다녀오는 것이 아니라 TLB에서 해당하는 물리 주소를 찾는다.
- 이 경우 메모리에 반복적으로 접근하는 것을 막아 가상 주소에 해당하는 물리 주소를 반복적으로 찾는 경우 시간을 단축할 수 있다.
페이징 시스템과 공유 메모리
- 서로 다른 프로세스들은 동일한 물리 주소를 가리킬 수 있음 (공간 절약, 메모리 할당 시간 절약)
그림 7. 프로세스 복사 1
- 위 그림에서 프로세스 A와 B에서 노랗게 표시된 영역은 공유되는 영역이라고 가정.
- 프로세스 A와 B에서 해당 주소만 하나의 동일한 물리 메모리 주소를 가리키게 한다면 메모리 공간과 메모리 할당 시간 절약 가능
그림 8. 프로세스 복사 2
- 프로세스 복사 후 물리 주소의 데이터 수정 시도 시 물리 주소를 복사할 수 있음 (copy-on-wirte)
- 이때 비로소 물리 주소의 데이터를 복사해서 프로세스 B의 페이지 테이블이 새로운 물리 주소를 가리키도록 함
페이징 시스템의 적용 정리
- 단순히 새로운 프로세스가 동일한 물리 주소를 가리키게 함으로써 프로세스의 생성 시간을 효율적으로 단축할 수 있다.
- 커널이든 사용자 영역의 공유 메모리든, 공유하는 데이터는 물리 메모리의 공간 공유를 통한 메모리 공간 절약이 가능한 것이다.
페이지 폴트 (Page Fault)
요구 페이징 (Demand Paging 또는 Demanded Paging)
- 프로세스의 모든 데이터를 메모리로 적재하지 않고, 실행 중에 필요한 시점에서만 메모리로 적재함
- 선행 페이징(anticipatory paging 또는 prepaging)의 반대 개념
- 선행 페이징: 미리 프로세스와 관련된 모든 데이터를 메모리에 올려놓고 실행하는 방식
- 더 이상 필요하지 않은 페이지 프레임은 다시 저장매체에 저장 (페이지 교체 알고리즘 필요)
페이지 폴트 인터럽트
- 어떤 페이지가 실제 물리 메모리에 없을 때 일어나는 인터럽트
- page fault 인터럽트가 일어나면 운영체제가 해당 페이지를 물리 메모리에 올림
그림 9. 페이지 폴트와 인터럽트
- 위 그림에서 유추할 수 있듯이, 페이지 폴트가 자주 일어나면 프로세스 실행 시간이 길어지게 된다.
- 페이지 폴트가 안 일어나게 하려면 향후 실행/참조될 코드/데이터를 미리 물리 메모리에 올리면 되는데, 사실 앞으로 어떤 일이 일어나서 어떤 데이터가 참조될 지 미리 예측하는 것은 쉽지 않다.
cf) 예전에 프로그램을 너무 많이 실행하게 되면 하드 디스크에서 소리가 나면서 마우스 반응도 느려지고 프로그램도 렉이 걸리는 경험을 해본 적이 있을텐데, 이 또한 페이지 폴트가 자주 일어나서 생긴 문제로 볼 수 있다.
- 프로세스 전환 시 메모리에 올라가 있던 데이터를 또 다시 저장매체에 접근해서 기록을 하게 되는데 (page swap) 이 또한 프로그램 반응 속도가 느려지는 문제에 기여한다. 필요한 프로그램만 사용하거나 메모리를 늘리는 방법이 있다.
페이지 교체 알고리즘
FIFO
FIFO (First In First Out) Page Replacement Algorithm
- 가장 먼저 들어온 페이지를 내린다.
- 물리 메모리에 페이지를 추가할 공간이 부족하면, 제일 먼저 들어온 페이지의 위치에 새로운 페이지를 올려 교체한다.
OPT
최적 페이지 교체 알고리즘 (OPTimal Replacement Algorithm)
- 앞으로 가장 오랫동안 사용하지 않을 페이지를 내린다.
- 일반 OS에서는 구현 불가
LRU
LRU(Least Recently Used) Page Replacement Algorithm
- 가장 오래 전에 사용된 페이지를 교체
- OPT 교체 알고리즘은 구현이 불가하므로, 대신 가장 사용한 지 오래된 페이지를 새로운 페이지와 교체하는 방식으로 구현
- 가장 많이 쓰이는 페이지 교체 알고리즘
LFU
LFU(Least Frequently Used) Page Replacement Algorithm
- 가장 적게 사용된 페이지를 새로운 페이지와 교체한다.
NUR
NUR(Not Used Recently) Page Replacement Algorithm
- LRU와 마찬가지로 최근에 사용하지 않은 페이지부터 교체하는 기법
- 각 페이지마다 참조 비트(R), 수정 비트(M)을 둠 (R, M)
- (0, 0), (0, 1), (1, 0), (1, 1) 순으로 페이지 교체
스레싱(Thrashing)
- 반복적으로 페이지 폴트가 발생해서, 과도하게 페이지 교체 작업이 일어나, 실제로는 아무 일도 하지 못하는 상황
- 프로그램은 수행하지 못한 채 페이지 폴트와 페이지 스왑만 반복적으로 수행
그림 10. 스레싱(Thrashing)
참고: 세그멘테이션 기법
세그멘테이션 기법이란
- 가상 메모리를 1) 서로 크기가 다른 2 ) 논리적 단위인 세그먼트(Segment)로 분할하는 기법
- 페이징 기법에서는 가상 메모리를 같은 크기의 블록으로 분할하는 것과 대조됨
- 예: x86 리얼모드(부팅)
- 리얼 모드는 메모리 공간을 최대 1GB 사용할 수 있는데, 이 공간을 CS(Code Segment), DS(Data Segment), SS(Stack Segment), ES(Extra Segment)로 세그먼트를 나누어서 메모리에 접근하게 구성되어 있다.
세그먼트 가상 주소
v = (s, d)
- s는 세그먼트 번호
- d는 해당 세그먼트 내에서 참조하는 위치
그림 11. 세그먼트 가상 주소
- 세그먼트 기법도 페이징 기법과 유사하게, 특정 레지스터가 가리키고 있는 세그먼트 테이블에 접근하여
- 해당 세그먼트에 매핑된 base 물리주소에 d에 해당하는 변위를 더해 해당 데이터의 물리 주소를 얻어낼 수 있다.
그림 12. 세그먼트 기법과 페이징 기법의 비교
- 각 구조의 논리적인 역할과 상관 없이 일률적으로 같은 크기의 페이지로 쪼개 물리 메모리에 올리는 페이징 기법과는 달리,
- 세그멘테이션 기법은 서로 크기가 다른, 논리적 단위인 세그먼트로 나누어, 서로 다른 크기의 세그먼트가 물리 메모리 위에 올라가는 것을 확인할 수 있다.
단편화 문제 (Fragmentation Problem)
- 내부 단편화 문제(Internal Fragmentation Problem) - (페이지 기법)
- 페이지 블록만큼 데이터가 딱 맞게 채워져 있지 않을 때 공간 낭비
- 외부 단편화 문제(External Fragmentation Problem) - (세그멘테이션 기법)
- 물리 메모리가 원하는 연속된 크기의 메모리를 제공해주지 못하는 경우
- 세그멘테이션/페이징 모두 하드웨어 지원 필요
- 다양한 컴퓨터 시스템에 대한 이식성을 중요시하는 리눅스는 페이징 기법을 기반으로 구현 (일부 CPU들이 페이징 기법만 지원하고 세그멘테이션 기법은 지원하지 않기 때문에)
너무 잘봤습니다. 감사합니다!