[OS] Virtual Memory
0. Virtual Memory
가상 메모리란, 컴퓨터 시스템에서 실제로 이용 가능한 메모리보다 더 큰 메모리 공간을 사용자에게 제공하는 메모리 관리 기법이다.
0-1. Virtual Memory의 주요 기능
가상 메모리의 주요 기능으로는 아래의 2가지가 있다.
- 물리 메모리보다 큰 주소 공간을 사용 가능하게 하여 제약을 완화한다(
Swapping
). - 프로세스 간 메모리 보호를 통해 안정성과 보안을 보장한다(
Protection
). - 각 프로세스에 독립적인 주소 공간을 제공하여 충돌 없이 병행 실행을 지원한다.
1. Virtual Memory의 핵심 개념
가상 메모리가 어떻게 물리적 제약을 완화하고 안전한 메모리 공유를 보장하는지 알기에 앞서, 핵심 개념부터 살펴보자.
1-1. Physical Address vs Logical Address
1-1-1. Physical Address
물리 주소
는 컴퓨터의 실제 하드웨어 메모리 장치의 주소를 나타낸다. 컴퓨터의 RAM이나 다른 하드웨어 장치에서 직접적으로 참조된다. 물리 주소는 하드웨어 수준에서만 의미가 있으며, 각 메모리 셀은 물리적 주소로 식별된다.
1-1-2. Logical Address
논리 주소
는 CPU가 생성한 가상 메모리 공간의 주소로, 실제 하드웨어의 주소와 다르다. 프로그램이 메모리에 접근할 때 사용하는 주소이며, 이 주소는 CPU의 관점에서 사용된다.
운영체제는 각 프로세스에 대해 페이지 테이블을 설정하고, MMU(Memory Management Unit)
는 이 페이지 테이블을 참고하여 논리 주소를 물리 주소로 변환한다. 이를 통해 여러 프로세스가 서로의 메모리를 간섭하지 않도록 보호하게 된다.
즉, CPU는 논리 주소를 생성하고, MMU가 논리 주소를 물리 주소로 변환하여 실제 메모리에서 데이터를 읽거나 쓰게 된다.
1-2. Base/Limit Register
페이지 테이블 방식이 아닌, 단순 주소 변환 방식(연속 할당 방식)에 사용되는 레지스터들이다. 주로 segmentation 기반 주소 변환에 사용된다. 접근하려는 주소가 유효한 주소인지 확인할 때 사용된다. 각 프로세스마다 Base/Limit 값
은 고유하므로 PCB(Process Control Block)
에 저장된다.
1-2-1. Base Register
베이스 레지스터는 현재 프로세스의 시작 물리 주소를 담고 있다. 예를 들어, CPU가 사용하려는 논리 주소가 100
이고 베이스 레지스터의 값이 13000
이라면, 물리 주소는 13000 + 100 = 13100
이 된다.
1-2-2. Limit Register
한계 레지스터는 프로세스가 접근할 수 있는 최대 논리 주소를 지정하며, 이 값을 초과한 접근은 보호 예외( trap
)을 발생시켜 다른 메모리 영역의 침범을 방지한다.
1-3. Page와 Frame
페이지와 프레임은 메모리를 일정한 크기의 공간으로 나누어 관리하는 단위
이다.
1-3-1. Page
페이지는 가상 메모리를 일정한 크기로 나눈 단위이며, 페이지 테이블을 통해 물리 메모리의 프레임과 매핑된다. 프로세스의 가상 주소 공간은 여러 개의 페이지로 구성되며, 각 페이지는 물리적인 메모리에 저장될 수도 있고 디스크에 스왑될 수도 있다.
1-3-2. Frame
프레임은 물리적인 메모리에서 페이지가 저장되는 공간이다. 즉, 메모리를 나누는 단위이다. 프레임은 페이지 테이블을 통해 페이지와 매핑된다.
항목 | 적재 대상 / 개념 | 의미 |
---|---|---|
Page | Frame에 적재됨 | 가상 메모리의 단위 |
Frame | RAM의 일부분 | 페이지가 올라가는 물리 메모리 공간 |
1-4. Page Table
Page
와 Frame
간의 매핑 정보를 저장하는 데이터 구조이다. 페이지 테이블은 프로세스마다 별도로 관리되며, 가상 주소의 페이지 번호를 물리 주소의 프레임 번호로 변환하는 데 사용된다.
2. Virtual Memory 구현 방식
2-1. Paging
“메모리를 고정 크기 단위로 나누는 방식”
대표적인 가상 메모리 구현 방식으로, 프로세스의 주소 공간을 동일한 크기의 페이지 단위로 나누어 물리적 메모리에 적재하는 방식이다. 적재되는 위치는 불연속적일 수 있다. 고정된 크기로 분할하기 때문에, 내부 단편화가 발생할 수 있다.
2-1-1. 기본 Paging
메모리를 페이지와 같은 크기의 프레임 단위로 미리 나누어 두고, 빈 프레임에 하나의 페이지를 할당한다. CPU가 사용하는 논리 주소를 페이지 번호(p)와 페이지 오프셋(d)로 나누어 주소 변환에 사용한다. 이 페이지 번호는 페이지 테이블의 index로 사용되고, 해당 인덱스의 entry에는 그 페이지의 물리적 메모리의 기준 주소, 즉 시작 위치가 저장되어 있다. 따라서 이 시작 위치에 페이지 오프셋을 더해주면 요청한 논리 주소에 매핑된 물리 주소를 얻을 수 있다.
예시를 보자(32bit 시스템, 페이지 크기 = 4KB).
두 개의 프로세스 A, B가 동일한 논리 주소 0x00001000
에 접근하려고 한다.
p = 1
, d = 0x000
- 프로세스 A의 경우,
- 페이지 테이블 :
entry[1] = 0x20000
-> 물리 주소 0x20000에 적재됨 - 결과 :
0x20000 + 0x000 = 0x20000
- 페이지 테이블 :
- 프로세스 B의 경우,
- 페이지 테이블 :
entry[1] = 0x50000
-> A와 다른 물리 주소 - 결과 :
0x50000 + 0x000 = 0x50000
- 페이지 테이블 :
논리 주소는 같지만, 페이지 테이블이 다르기 때문에 물리 주소가 다르다.
2-1-2. Hierarchical Page Table
32비트 주소 체계를 사용하는 시스템은 2^32 = 4,294,967,296
개의 서로 다른 주소를 표현할 수 있으므로, 가상 주소 공간은 최대 4GB(2^32 * 1Byte(메모리 최소 단위))이다. 또한 32비트 시스템에서는 보통 페이지 크기가 4KB(2¹² bytes)다. 4GB 프로그램을 실행해야 한다면 1M개의 페이지가 생성된다.
따라서 페이지 테이블도 1M개의 엔트리를 생성한다. 각 항목 당 4바이트(32비트)의 주소를 표현해야 하기 때문에, 페이지 테이블은 결국 1M X 4B = 4MB 크기의 메모리 공간을 필요로 하게 된다.
실행되는 프로그램이 많아질수록 메모리 공간 낭비가 심해지는데, 심지어 전체 프로그램 주소 공간 중 극히 일부분만 사용되는 경우를 생각하면, 전체 페이지 테이블이 메모리 공간에 올라가는 것은 심각한 메모리 낭비이다. 이를 해결하기 위해 사용되는 것이 Hierarchical Page Table(계층적 페이지 테이블)
이다.
2 level paging
기법을 예시로 살펴 보자.
주소 변환을 위해 외부 페이지 테이블
과 내부 페이지 테이블
두 단계를 거친다.
먼저, 외부 페이지 테이블로부터 내부 페이지 테이블의 주소를 얻는다. 그리고 다시 내부 페이지 테이블로부터 물리적 메모리 위치(프레임 시작 위치) 정보를 얻는다. 사용되지 않는 주소 공간에 대해서는 외부 페이지 테이블의 항목을 NULL로 설정해, 이에 대응하는 내부 페이지 테이블을 생성하지 않는다. 이를 통해 메모리 공간 낭비를 줄일 수 있다.
32비트 시스템에서 페이지 크기가 약 4KB(정확히는 2^12)이므로, 하나의 페이지 내에서 바이트 오프셋을 표현하기 위해서는 12비트가 필요하다. 따라서 최하위 12비트는 오프셋으로 사용된다.
0000 0000 0000 0000 0000 / 0000 0000 0000
[24bit] / [12bit(offset)]
다음으로 내부 페이지 번호를 저장해야 하는데, 하나의 하위 페이지 테이블은 최대 4KB 공간만 사용한다(하나의 페이지를 테이블로 쓰기 때문). 각 페이지 테이블 항목이 4바이트(32비트)이고, 하나의 페이지 크기가 4KB(2^12 Bytes)이므로, 한 페이지에는 총 2^12 / 2^2 = 2^10 = 1024
개의 항목을 저장할 수 있다. 즉, 내부 페이지 테이블을 인덱싱하기 위해서는 10비트가 필요하다.
0000 0000 00/00 0000 0000 / 0000 0000 0000
[10bit] / [10bit(inner page table)] / [12bit(offset)]
나머지 10비트는 외부 페이지 테이블 인덱스로 사용한다.
0000 0000 00/00 0000 0000 / 0000 0000 0000
[10bit(outer page table)] / [10bit(inner page table)] / [12bit(offset)]
여러 번의 테이블 접근이 필요하기 때문에, level이 깊어질수록 시간 오버헤드가 발생한다. 이를 보완하기 위해, 최근 접근한 페이지 번호와 프레임 번호를 저장해두는 고속 캐시인 TLB(Translation Lookaside Buffer
를 사용하여 주소 변환 시간을 단축한다. 보통 4 level로 구성하면 시간 오버헤드는 그렇게 크지 않지만, 효율적인 메모리 공간 사용 효과를 기대할 수 있다.
2-1-3. Inverted Page Table
메모리 주소 공간의 효율을 위해 사용하는 극단적인 방법이다. Inverted Page Table 기법은 시스템 전체에 페이지 테이블을 하나만 만들어둔다.
Inverted Page Table에서는 각 물리적 프레임마다, 해당 프레임에 저장된 페이지가 어떤 프로세스의 어떤 페이지인지 정보를 저장한다. 즉, 프레임 기준의 역방향 매핑 테이블이다. 위 그림에서 pid
는 프로스세 아이디를, p
는 페이지 번호를 의미한다. 페이지 주소 변환 요청이 들어오면, 논리 주소를 담은 페이지가 메모리에 존재하는지 여부를 판단하기 위해 페이지 테이블 전체를 탐색한다. 때문에 associative register(연관 레지스터)
에 페이지 테이블을 저장한 뒤, 병렬 탐색을 통해 시간적 효율성을 높인다.
2-2. Segmentation
“프로세스 주소 공간을 의미 단위로 나누는 방식”
프로세스의 주소 공간을 고정된 크기가 아닌, 의미 있는 단위(segment
)로 분할하는 방식이다.
ex. code segment
, data segment
, stack segment
실제 사용되는 크기만큼 나누기 때문에, 각 세그먼트는 크기가 다를 수 있다.
Segmentation 방식에서 논리 주소는 다음과 같은 구조를 가진다.
logical address
= (segment 번호
+ segment 내 offset
) = (s
, d
)
MMU는 세그먼트 테이블을 참고해, 세그먼트의 base
주소와 limit
을 얻어 물리 주소로 변환한다.
2-2-1. Segmentation 주소 변환 방식
logical address
= (s
, d
)
s
: segment 번호
d
: offset
physical address
= segment_table[s].base + d
condition
: d < segment_table[s].limit
2-2-2. Segmentation 방식의 장점 및 단점
- 장점
- 각 segment는 독립적이므로 메모리 보호 및 접근 제어가 용이하다.
- 프로세스의 논리적 구조(코드, 데이터, 스택 등)와 일치하여 메모리 관리가 직관적이다.
- 단점
- 외부 단편화 발생(크기가 제각각이므로)
- 할당/해제 시 관리가 복잡하다.
2-3. Paging + Segmentation 혼합 기법
현대 시스템에서 많이 사용되는 방식이다. Paging 기법을 통해 Segment를 고정된 크기 단위로 나누고, 물리 메모리에 불연속적으로 배치하여 단편화를 줄인다.
logical address
= segment 번호
+ segment 내 페이지 번호
+ offset
segmentation
: 프로세스 구조를 코드/데이터/스택 등으로 나눔
paging
: 각 세그먼트를 페이지 단위로 잘라서 물리 메모리에 불연속적으로 배치
2-3-1. Paging + Segmentation 주소 변환 과정
segment 번호
를 통해segment table
에서 해당 segment에 연결된 페이지 테이블의 시작 주소(base)를 얻는다.segment 내 페이지 번호
를 통해 해당 페이지의 물리 프레임 번호를 얻는다.- 최종
physical address
=frame 시작 주소
+offset
2-3-2. Paging + Segmentation의 장점 및 단점
- 장점
- Segmentation의 논리적 분할 이점 + Paging의 효율적 메모리 관리
- 내부 단편화 없음
- segment 단위로 보안, 보호, 공유 기능 가능
- 단점
- 주소 변환 단계가 늘어나므로 오버헤드 증가
- 하드웨어가 더 복잡해짐
2-3-3. Paging vs Segmentation 정리표
항목 | Paging | Segmentation |
---|---|---|
나누는 기준 | 고정 크기 페이지 | 의미 단위(코드, 데이터 등) |
단편화 유형 | 내부 단편화 가능 | 외부 단편화 가능 |
보호 단위 | 페이지 단위 | 세그먼트 단위 |
3. 메모리 매핑 및 주소 변환
3-1. MMU(Memory Management Unit)
가상 메모리의 논리 주소를 물리 주소로 변환해주는 하드웨어 장치다. OS를 통해 페이지 테이블 등에 접근하고 변환 작업을 수행한다.
현대 CPU들은 대부분 내부에 MMU가 들어 있다(아래 나올 TLB
는 MMU 안에 있다).
3-2. TLB(Translation Lookaside Buffer)
자주 참조되는 Page Table Entry
를 저장하는 캐시이다. TLB가 없을 경우, 논리 주소를 변환하기 위해 CPU는 메모리에 두 번 접근해야 한다.
- 페이지 테이블 참조를 위해 메모리 접근
- 페이지 테이블 값 기반으로 메모리에 접근
이는 시간이 오래 걸리는 작업이므로, 최근에 발생한 논리 - 물리 주소 변환 테이블을 TLB에 저장한다. CPU가 논리 주소로 메모리에 접근하려고 할 때, TLB를 먼저 확인하여 매핑이 존재하면 바로 해당 물리 주소에 접근한다.
당연히 메모리에 두 번 접근하는 것보다 성능이 좋아야 하므로, 작고 빠르며 비싸다. MMU 내부에 위치한다.
3-3. Page Fault와 처리 과정
가상 메모리에서 물리 메모리에 올려두지 않은 페이지에 대한 요청이 들어왔을 때 발생하는 예외이다. Page Fault가 발생하면 운영 체제는 해당 페이지를 메모리로 가져와서 프로그램이 계속 작동하게 한다. (이해되지 않는다면 4번 Swap을 읽고 오자.)
3-3-1. Page Fault의 종류
-
Major Page Fault 요청한 페이지가 물리 메모리로부터
page-out
되어 보조기억장치의 가상 메모리에 저장되어 있다면 해당 페이지를 다시 물리 메모리로page-in
해야 하는데, 이런 상황을 Major Page Fault라고 한다. Major Page Fault는 Disk I/O를 발생시킨다(성능 저하 유발). -
Minor Page Fault 요청한 페이지가 물리 메모리에는 Load 되어 있지만, MMU에는 Load 되어있지 않다고 표시된 경우 이를 Minor Page Fault라고 한다.
-
Invalid Page Fault 블루 스크린 원인 중 하나이다. 요청한 페이지가 존재하지 않는 주소 공간을 참조하거나, 페이지를 쓰기 불가능한 영역에 쓰려고 할 때 발생하는 Page Fault이다. 이 경우에는 Page Fault Handler가
Segmentation Fault
를 발생시킨다. 결과는 보통 커널 패닉(블루스크린)으로 나타난다.
3-3-2. Page Fault 처리 과정
- page table을 확인한다.
- 필요한 page가 없다면 운영체제에 page fault trap을 전달한다. 2-1. 동작하고 있던 프로세스의 PCB는 메모리에 저장한다.
- 운영체제는 다른 page table을 확인하여, 심각한 문제가 있다면 프로세스를 중지시키고, 단순히 메모리에 올라와 있지 않은 경우라면 backing store에서 해당 페이지를 찾는다.
- 찾은 page를 물리 메모리의 빈 frame에 올린다. 만약 free frame이 없다면 페이지 교체 알고리즘을 통해
page-in
,page-out
을 수행한다. 이 때, 프로그램은 wait queue에 들어가서 대기한다. 4-1. free frame을 찾고 있을 때 CPU는 다른 프로그램에게 할당된다. 4-2. 찾았다면 CPU를 점유하고 있던 프로세스의 PCB를 저장하고 page fault를 발생시킨 프로그램의 PCB를 가져온다. - page가 물리 메모리에 적재되면, page table을 업데이트한다.
- page fault를 발생시킨 코드를 다시 시작한다.
4. Swap 및 물리 메모리 부족 시 처리
물리 메모리에 필요한 공간 확보가 불가능할 경우, 메모리에 있는 우선순위가 낮은 페이지를 보조기억장치인 하드디스크에 저장한다. 만약 CPU에서 보조기억장치에 있는 페이지가 필요한 경우, 해당 페이지를 현재 메모리에 있는 우선순위가 낮은 페이지와 바꾼다. 이를 Swap
이라고한다.
4-1. Swap 영역
Swap space(스왑 영역)
이란, Swap할 때 사용되는 하드디스크 공간을 말한다.
Virtual Machine이나 컴퓨터에 Linux를 설치하면서 partition을 나눌 때 봤던 그 Swap 영역이다.
4-2. 페이지 교체 알고리즘
Swap이 일어날 때 사용되는 알고리즘에는 무엇이 있을까?
4-2-1. FIFO(First In First Out)
이름 그대로 메모리에 올라온 페이지 순서대로 스왑을 진행한다.
4-2-2. LRU(Least Recently Used)
가장 오랫동안 사용하지 않은 페이지 순으로 교체한다. 가장 오랫동안 사용하지 않았던 데이터라면 앞으로도 사용할 확률이 적을 것이라는 가정으로 만들어진 알고리즘이다.
4-2-3. Clock(Second Chance) Algorithm
시계처럼 돌아서 시계 알고리즘이라고 불린다. 2번째 기회를 주기 때문에 Second Chance 알고리즘으로도 불린다.
기본 정책은 오래되고 사용하지 않는 페이지를 교체한다는 것이다.
- 동작 방식
- 페이지들을 참조할 때, 하드웨어는 Reference Bit를 1로 세팅한다.
- 운영체제가 FIFO Queue에서 스왑될 페이지를 확인한다.
- 만약 페이지의 Reference Bit가 1이면 0으로 바꾸고 다시 queue에 넣는다.
- 만약 페이지의 Reference Bit가 0이면 해당 페이지를 Swap한다.
5. Virtual Memory의 장점과 단점
5-1. 장점
- 프로세스 격리 : 각 프로세스는 독립된 가상 메모리 공간을 가지므로 하나의 프로세스가 다른 프로세스의 메모리를 오염시키지 않는다.
- 큰 주소 공간 제공 : 물리 메모리의 크기 한계를 넘어서, 디스크의 스왑 공간을 활용 하여 넓은 주소 공간을 제공한다.
- 메모리 단편화 완화 : 프로세스를 페이지 단위로 나누고, 물리 메모리 또한 이에 맞춰 프레임 단위를 설정하여 외부 단편화를 해결한다. 또한 프로세스를 논리적 크기인 세그먼트로 나누어 내부 단편화를 해결할 수 있다. 두 방법을 조합하여 효율적으로 단편화를 해결할 수 있다.
- 실행 중 프로그램 동적 로딩 가능 : 필요한 페이지가 메모리 상이 아닌, 스왑 공간에 있을 경우 동적으로 로딩하여 프로그램이 지속 가능하게 해준다.
5-2. 단점
- 속도 저하
- 페이지 폴트 : 필요한 페이지가 메모리 상이 아닌, 스왑 공간에 있을 경우 이를 메모리에 로드하는 과정에서 오버헤드가 발생한다.
- TLB 미스 : 필요한 페이지 테이블 엔트리가 TLB에 캐시 되어 있지 않을 경우, 무의미한 확인 과정을 한번 수행한 것이므로 오버헤드가 되어버린다.
- 복잡한 하드웨어 필요 : 주소 변환에 사용되는 MMU, 주소 확인을 위한 오버헤드를 줄이기 위한 TLB 캐시 등 많은 하드웨어를 필요로 한다.
6. 실제 사례로 보는 가상 메모리
6-1. 메모리 영역 구분
6-2. malloc의 동작 과정
6-2-1. malloc
malloc(size_t size)
는 요청한 크기만큼의 바이트 단위 메모리 블록을 힙에서 할당하고, 그 시작 주소를 반환한다. (new
는 할당 후 생성자까지 호출한다)
6-2-2. malloc 수행 과정
-
사용자 호출
int* arr = (int*)malloc(100 * sizeof(int));
-
C 라이브러리 할당자 호출 내부적으로
malloc()
은 C 런타임 라이브러리(glibc 기준)에서 제공하는 힙 관리자(ptmalloc)을 호출한다. - 힙에서 관리 중인 free block 탐색
- 이미 힙에 있는 free block 중 적절한 크기가 있는지 확인
- 있다면 해당 block에서 크기에 맞게 일부를 잘라내서 반환
- 필요 시 시스템 호출로 가상 메모리 요청
- 적당한 블록이 없으면
brk()
또는mmap()
같은 시스템 콜(리눅스 기준)을 통해 운영체제에 메모리를 요청 - 이 요청은 실제 물리 메모리를 확보하는 것이 아니라, 가상 주소 공간 상의 새로운 페이지를 힙에 추가하는 것
- 적당한 블록이 없으면
- 메모리 반환 최종적으로 가상 주소를 반환하며, 해당 영역은 프로세스의 힙 영역에 매핑된다.
6-2-3. 지연 할당(lazy allocation)
- 초기 힙은
brk()
시스템 콜로 확장됐다. - 많은 현대 시스템에서는
mmap()
으로 페이지 단위로 힙 영역을 확장한다. - 메모리가 실제로 물리 메모리에 올라가는 시점은 페이지가 실제 접근되는 순간(Page Fault 발생 시) 이다. -> 지연 할당
6-3. 가상 메모리와 malloc의 연관성
malloc
/new
는 직접 물리 메모리를 할당하지 않는다.- 운영체제를 통해 가상 메모리 주소 공간에 페이지 단위로 힙 영역을 매핑한다.
- 그 주소는 사용자 프로세스에 연속된 것처럼 보이지만, 실제 물리 메모리는 불연속적일 수 있다.
- 이는 가상 메모리 시스템이 제공하는 중요한 이점 중 하나다.
6-4. 그럼 배열도 꼭 물리 메모리 상에 연속이 아닐 수도 있겠네?
배열의 크기가 작으면 물리 메모리 상에서도 연속될 가능성이 높지만, 배열이 매우 클 경우에는 가상 주소 공간에서는 연속이더라도 물리 메모리에서는 연속되지 않을 수 있다.
일반적으로 선언하는 int arr[100]
같은 작은 배열은 수 킬로바이트 미만이기 때문에, 하나 또는 몇개의 페이지(보통 4KB 단위) 안에 충분히 들어간다. 이 경우, 해당 배열은 가상 주소 뿐 아니라 물리 메모리에서도 연속된 frame에 위치할 가능성이 높다. 특히 스택에 할당되는 지역 배열은 커널이 스택 프레임을 한 번에 할당하므로, 비교적 연속된 메모리에 놓일 가능성이 더 높다.
하지만 int* bigArr = new int[10000000]; (약 40MB)
의 경우를 생각해 보자. 이 배열은 new
를 통해 힙 영역에 연속된 가상 주소 공간을 요청한다. OS는 내부적으로 10MB가 넘는 크기의 가상 주소 공간을 예약하고, 해당 주소 공간을 여러 개의 페이지(보통 4KB)로 나누어 할당한다. 이 때, 각 페이지는 물리 메모리 상에서 불연속적인 frame에 매핑될 수 있다. 즉, 가상 주소는 연속적이지만 물리 주소는 불연속인 상황이 가능하다. 페이지 단위로 물리 주소를 매핑하기 때문에 이런 일이 발생한다.
배열 크기 | 가상 주소 | 물리 주소 |
---|---|---|
작음 (수 KB 이하) | 연속 | 연속 가능성 높음 |
큼 (수 MB 이상) | 연속 | 불연속 가능성 큼 |
6-5. 메모리 부족, 누수와 가상 메모리의 상관관계
6-5-1. 메모리 부족
가상 메모리 덕분에 프로세스는 큰 주소 공간을 사용할 수 있지만, 실제 메모리(RAM + Swap)의 한계는 여전히 존재한다. 가상 메모리는 논리적으로 메모리를 제공하지만, 실제 데이터를 저장하려면 물리 메모리가 필요하다. Swap이 꽉 찼거나, 커널이 프로세스에 허용한 메모리 제한(ulimit
)을 초과하면 할당에 실패한다.
프로세스가 할당한 가상 메모리를 실제 물리 메모리(RAM) 또는 디스크(Swap)에 매핑할 수 없을 때, malloc
, new
는 NULL/nullptr을 반환한다.
6-5-2. 메모리 누수(leak)
프로세스가 할당된 메모리를 더 이상 사용하지 않는데도 해제하지 않는 현상. 메모리 누수는 프로세스 내부의 가상 주소 공간을 소모한다. 프로세스가 종료되면 OS는 전체 가상 주소 공간과 그에 매핑된 물리 메모리/Swap 공간을 회수한다.
6-6. Segmentation Fault, Access Violation의 원인과 가상 메모리
Segmentation Fault(Linux, Unix)
, Access Violation(Windows)
모두 잘못된 메모리 접근에 의해 발생하는 오류이며, 가상 메모리 시스템이 이를 감지하여 커널이 인터럽트를 발생시킨다.
6-6-1. 발생하는 이유
원인 | 설명 |
---|---|
접근 권한 위반 | 읽기 전용 페이지에 쓰기 시도, 실행 불가능한 영역 실행 |
매핑되지 않은 주소 접근 | 아직 할당되지 않은 페이지 접근 (ex. nullptr , 쓰레기 포인터) |
스택 오버플로우 | 스택이 제한된 크기를 초과해, guard page 침범 |
잘못된 포인터 연산 | 해제된 포인터 사용 (dangling pointer ) |
6-6-2. 가상 메모리 시스템이 감지하는 과정
- 프로그램이 잘못된 가상 주소를 접근
- MMU가 해당 주소를 페이지 테이블에서 확인
- 존재하지 않거나 접근 권한이 맞지 않으면 페이지 폴트 발생
- 커널이 검사 후, 불가능한 접근이면 SIGSEGV(Unix)/Access Violation Exception(Windows) 발생
- 프로그램 강제 종료
Leave a comment