메모리 관리를 알아보기 전 메모리 구조에 대해 아주 간단하게만 정리해보겠습니다.
메모리 구조 기본
1. 주소 공간 (Address Space)
- 물리 주소: 실제 메모리(RAM) 상의 위치.
- 논리 주소(가상 주소): CPU와 프로그램이 인식하는 주소. OS가 MMU를 통해 물리 주소로 변환.
- 이를 통해 여러 프로세스가 동시에 실행 가능.
2. 사용자 영역 vs 커널 영역
- 사용자 영역: 일반 프로그램 실행 공간.
- 커널 영역: OS 핵심 기능(시스템 콜, 드라이버 등)이 동작하는 공간.
- 보호 모드로 실행되어 안정성을 보장.
- 중요한 운영체제 코드를 사용자 프로그램이 손상시키는 것을 방지
3. 프로세스 메모리 구조
- 코드(Code) 영역: 실행할 프로그램의 코드가 저장되는 공간입니다. 읽기 전용입니다.
- 데이터(Data) 영역: 전역 변수와 정적(static) 변수가 저장됩니다. 프로그램 시작과 함께 할당되고 종료 시 소멸됩니다.
- 힙(Heap) 영역: 프로그래머가 동적으로 할당하는 메모리 공간입니다. (예: C의
malloc(), Java의 new). 낮은 주소에서 높은 주소 방향으로 할당됩니다.
- 스택(Stack) 영역: 함수 호출 시 생성되는 지역 변수, 매개변수, 리턴 주소 등이 저장됩니다. 높은 주소에서 낮은 주소 방향으로 할당됩니다.
운영체제 레벨의 메모리 관리
1. 메모리 할당 방식
연속 메모리 할당(Contiguous Allocation)
프로세스를 메모리의 연속적인 공간에 통째로 할당하는 방식입니다.
- 고정 분할 방식: 메모리를 일정 크기 블록으로 나눔 → 내부 단편화 발생.
- 가변 분할 방식: 프로세스 크기에 따라 동적으로 분할 → 외부 단편화 발생.
비연속 메모리 할당(Non-contiguous Allocation)
하나의 프로세스를 물리 메모리의 여러 분산된 영역에 나누어 할당하는 방식입니다. 연속 메모리 할당의 단편화 문제를 해결하기 위해 고안되었습니다.
- 대표 방식: 페이징(Paging), 세그멘테이션(Segmentation)
내부 단편화
프로세스가 분할된 공간보다 작을 경우, 남는 공간이 발생하는 경우
외부 단편화
프로세스가 종료되어 메모리를 반납하면 작은 빈 공간들이 생기는데, 이 공간들이 너무 작아서 다른 프로세스를 할당하지 못하는 경우
2. 페이징 (Paging)
- 개념
- 메모리를 고정 크기 블록(프레임)으로 나누고, 프로세스를 같은 크기의 페이지로 나눠 저장.
- 논리 주소 = (페이지 번호, 오프셋)
- 물리 주소 = (프레임 번호, 오프셋)
- 구조 요소
- 페이지(Page): 프로세스의 단위.
- 프레임(Frame): 물리 메모리의 단위.
- 페이지 테이블: 페이지 번호 → 프레임 번호 매핑.
- 다단계 페이지 테이블: 큰 주소 공간을 효율적으로 관리. (ex. 2-level, 3-level)
- TLB (Translation Lookaside Buffer): 주소 변환 캐시 → 페이지 테이블 접근 속도 개선.
- 장점: 외부 단편화 없음.
- 단점: 내부 단편화 존재, 페이지 테이블 관리 비용 발생.
3. 세그멘테이션 (Segmentation)
- 개념
- 메모리를 논리적 단위(코드, 함수, 데이터 등)로 나누어 관리.
- 각 세그먼트는 크기가 가변적.
- 논리 주소 = (세그먼트 번호, 오프셋).
- 구조 요소
- 세그먼트 테이블: (base, limit) 값 저장.
- base: 세그먼트 시작 주소.
- limit: 세그먼트 길이.
- 장점: 프로그램의 논리 구조와 메모리 관리가 잘 매칭됨.
- 단점: 외부 단편화 문제 발생.
4. 가상 메모리 (Virtual Memory)
- 개념: 프로세스가 실제 물리 메모리보다 큰 주소 공간을 사용할 수 있도록 하는 기술.
- 요구 페이징(Demand Paging)
- 실제로 필요할 때만 페이지를 메모리에 로드.
- page fault 발생 시 디스크에서 불러옴.
- 페이지 교체 알고리즘 (자세한 건 3번에서 다룸)
- 페이지 부재(page fault) 시 어떤 페이지를 내보낼지 결정.
- 스래싱(Thrashing)
- 페이지 교체가 너무 잦아 CPU보다 디스크 I/O에 시간이 소모되는 현상.
- 해결: 작업 집합(Working Set) 모델 사용 → 자주 쓰는 페이지는 반드시 메모리에 유지.
페이지 교체 알고리즘 (자세히 정리)
프로세스 실행 중 page fault 발생 시, 메모리에 빈 프레임이 없으면 기존 페이지를 내보내야 함. 이때 사용하는 정책이 페이지 교체 알고리즘.
1. FIFO (First-In First-Out)
- 원리: 가장 먼저 들어온 페이지를 교체.
- 장점: 구현 단순, 큐 구조로 관리.
- 단점: 오래 있었지만 자주 사용하는 페이지가 교체될 수 있음 → Belady’s Anomaly 발생 가능 (프레임 수가 늘어나도 page fault가 줄지 않는 경우).
2. LRU (Least Recently Used)
- 원리: 가장 오랫동안 사용되지 않은 페이지를 교체.
- 장점: 실제 사용 패턴과 유사 → 성능 우수.
- 단점: 시간/공간 비용이 큼 (최근 사용 내역을 기록해야 함).
3. LFU (Least Frequently Used)
- 원리: 참조 횟수가 가장 적은 페이지 교체.
- 장점: 자주 쓰이는 페이지는 보호됨.
- 단점:
- 최근 급격히 많이 쓰이던 페이지도 과거 참조 횟수가 낮으면 교체될 수 있음.
- 구현 복잡, 관리 비용 높음.
✅ 비교 요약
- FIFO: 단순하지만 비효율 가능.
- LRU: 현실적인 접근, 성능 우수.
- LFU: 특정 패턴에서 효율적이지만 구현 복잡.
메모리 관리에 대해서 설명하기 전에 메모리 구조를 알려주셔서 머릿속에서 정리가 더 편했습니다