CS

[운영체제] 2. 메모리

말하는 알감자 2026. 5. 3. 12:05

2.1 메모리 계층 

메모리 계층은 레지스터 → 캐시 → 메모리(RAM) → 저장장치(HDD/SDD) 순으로 구성됨
     속도 빠름, 용량 작음, 가격 비쌈
             ▲
             │   ┌─────────────┐
             │   │   레지스터    │  ← CPU 안에 있는 작은 메모리
             │   ├─────────────┤
             │   │  캐시(L1,L2) │  ← 빠른 임시 저장소
             │   ├─────────────┤
             │   │  메모리(RAM)  │  ← 주기억장치
             │   ├─────────────┤
             │   │  HDD / SSD  │  ← 보조기억장치
             ▼   └─────────────┘
    속도 느림, 용량 많음

계층별 특징

계층 휘발성 속도 용량
레지스터 휘발성 가장 빠름 가장 적음
캐시 (L1, L2) 휘발성 빠름 적음
주기억장치 (RAM) 휘발성 보통 보통
보조기억장치 (HDD/SDD) 비휘발성 느림 많음

왜 계층 구조가 존재하는가?

계층 구조가 있는 이유는 경제성캐시 때문

  • 16GB RAM → 약 8만 원
  • 16GB SDD → 훨씬 더 싼 가격

계층 위로 올라갈수록 가격을 비싸지는데 용량은 작아지고 속도는 빨라지는 특징이 있음
이러한 경제성 때문에 계층을 둬서 관리

💡 로딩 중 메시지 = HDD/SSD(보조기억장치) → RAM(주기억장치)으로 데이터를 전송하는 과정이 아직 끝나지 않음을 의미


2.1.1 캐시 (Cache)

캐시는 데이터를 미리 복사해 놓는 임시 저장소이자 빠른 장치와 느린 장치에서 속도 차이에 따른 병목 현상을 줄이기 위한 메모리를 말함

실제로 메모리와 CPU 사이의 속도 차이가 너무 크기 때문에, 그 중간에 레지스터 계층을 두어 속도 차이를 해결
이렇게 속도 차이를 해결하기 위해 계층과 계층 사이에 있는 계층을 캐싱 계층이라고 함

지역성의 원리

캐시를 직접 설정할 때는 자주 사용하는 데이터를 기반으로 설정해야 함
자주 사용하는 데이터의 근거가 되는 것이 바로 지역성

시간 지역성 (Temporal Locality)

최근 사용한 데이터에 다시 접근하려는 특성

// 변수 i는 매 반복마다 계속 접근됨 → 시간 지역성
for (let i = 0; i < 10; i += 1) {
    arr[i] = i;
}

공간 지역성 (Spatial Locality)

최근 접근한 데이터를 이루고 있는 공간이나 그 가까운 공간에 접근하려는 특성

// 배열 arr의 각 요소에 순서대로 연속 접근 → 공간 지역성
for (let i = 0; i < 10; i += 1) {
    arr[i] = i;  // arr[0], arr[1], arr[2]... 연속된 공간 접근
}

2.1.2 캐시히트와 캐시 미스

용어 설명
캐시히트 캐시에서 원하는 데이터를 찾은 경우
CPU 내부 버스를 기반으로 작동하여 빠름
캐시미스 해당 데이터가 캐시에 없어 주 메모리로 가서 데이터를 찾아오는 것
시스템 버스를 기반으로 작동하여 느림

캐시매핑

캐시매핑이란 캐시가 히트되기 위해 매핑하는 방법을 말함
CPU 레지스터와 주 메모리(RAM) 간에 데이터를 주고받을 때를 기반으로 설명
이름 설명
직접 매핑 (Diredted Mapping) 메모리 1 ~ 100이 있고 캐시가 1 ~ 10이 있다면 1 : 1~10, 2 : 20~30 이런 식으로 매핑
처리가 빠르지만 충돌 발생이 잦음
연관 매핑 (Associative Mapping) 순서를 일치시키지 않고 관련 있는 캐시와 메모리를 매핑
충돌이 적지만 모든 블록을 탐색해야 해서 속도가 느림
직접 연관 매핑 (Set Associative Mapping) 직접 매핑과 연관 매핑을 합쳐놓은 것
캐시 1~5에는 1~50의 데이터를 무작위로 저장

웹 브라우저의 캐시

소프트웨어적인 대표적인 캐시로는 웹 브라우저의 작은 저장소 쿠키, 로컬 스토리지, 세션 스토리지가 있음

저장소 만료 기한 용량 특징
쿠키 있음 4KB same site 옵션을 strict로 설정하지 않으면 다른 도메인에서 요청 시 자동 전송
httponly 옵션을 
서버, 클라이언트 어디에서도 수정 가능하지만 보통 서버에서 정함
로컬 스토리지 없음 10MB 웹 브라우저를 닫아도 유지됨
도메인 단위로 저장
클라이언트에서만 수정 가능
세션 스토리지 없음 5MB 탭 단위로 생성
탭을 닫을 때 데이터 삭제
클라이언트에서만 수정 가능

💡 데이터베이스의 캐싱 계층 : 메인 데이터베이스 위에 레디스(redis) 데이터베이스 계층을 '캐싱 계층'으로 두어 성능을 향상하기도 함


2.2 메모리 관리 

운영체제의 대표적인 할 일 중 하나. 컴퓨터 내의 한정된 메모리를 극한으로 활용

2.2.1 가상 메모리 (Virtual Memory)

가상 메모리는 메모리 관리 기법의 하나로 컴퓨터가 실제로 이용 가능한 메모리 자원을 추상화하여 이를 사용하는 사용자들에게 매우 큰 메모리로 보이게 만드는 것
 프로세스 A    프로세스 B    프로세스 C
가상 0x0000  가상 0x0000  가상 0x0000
    ↓           ↓            ↓
   ┌─────────────────────────┐
   │     MMU (메모리관리장치)    │
   └─────────────────────────┘
    ↓           ↓            ↓
RAM 0x1000  RAM 0x5000  RAM 0x9000
        (실제로는 서로 다른 공간)

각 프로세스는 "혼자 메모리 전체를 사용하는" 착각을 하게 됨
개발자는 실제 메모리의 물리적 위치를 신경 쓰지 않고 프로그램을 구축할 수 있게 됨

가상 주소 VS 실제 주소

용어 설명
가상 주소 (logical address) 프로세스가 바라보는 주소. 각 프로세스에게 독립적으로 부여
실제 주소 (physical address) RAM 위에 실제로 존재하는 주소

가상 주소는 MMU(메모리 관리 장치)에 의해 실제 주소로 변환됨
가살 메모리는 가상 주소와 실제 주소가 매핑되어 있는 페이지 테이블로 관리됨

TLB

TLB는 메모리와 CPU 사이에 있는 주소 변환을 위한 캐시
페이지 테이블에 있는 리스트를 보관하며, CPU가 페이지 테이블까지 가지 않아도 되도록 속도를 향상하는 캐시 계층

스와핑 (Swapping)

가상 메모리에는 존재하지만 실제 메모리인 RAM에는 현재 없는 데이터나 코드에 접근할 경우 페이지 폴트가 발생
이때 메모리에서 당장 사용하지 않는 영역을 HDD/SSD로 옮기고, HDD/SDD의 일부분을 마치 메모리처럼 불러와 쓰는 것이 스와핑
이를 통해 마치 페이지 폴트가 일어나지 않은 것처럼 만듦

페이지 폴트 (Page Fault)

프로세스의 주소 공간에는 존재하지만 지금 이 컴퓨터의 RAM에는 없는 데이터에 접근했을 경우 발생
프로세스 가상 주소 공간 (페이지 테이블)
        ↓
   RAM에 있음? ────YES───→ 정상 접근
        ↓ NO
   페이지 폴트 발생
        ↓
  HDD/SSD(스왑 영역)에서 RAM으로 불러옴
        ↓
    스와핑 발동

페이지 폴트 처리 과정

1. CPU가 물리 메모리를 확인하여 해당 페이지가 없으면 트랩을 발생시켜 운영체제에 알림
2. 운영체제는 CPU 동작을 잠시 멈춤
3. 운영체제가 페이지 테이블을 확인하여 가상 메모리에 페이지가 존재하는지 확인
    없으면 프로세스를 중단하고 물리 메모리에 비어있는 프레임을 찾음
    물리 메모리에도 없다면 스와핑 발동
4. 비어있는 프레임에 해당 페이지를 로드하고 페이지 테이블 최신화
5. 중단되었던 CPU를 다시 시작

💡 페이지(page)와 프레임(frame)
페이지는 가상 메모리를 사용하는 최소 크기 단위
프레임은 실제 메모리를 사용하는 최소 크기 단위

2.2.2 스레싱(Thrashing)

메모리의 페이지 폴트율이 높은 것을 의미하며, 컴퓨터의 심각한 성능 저하를 초래 
드레싱의 근본 원인은 RAM이 부족해서 프로세스들이 서로 페이지를 차지하려고 경쟁하는 것

스레싱 발생 원인 (악순환)

너무 많은 프로세스가 메모리에 올라옴
        ↓
스와핑이 빈번하게 발생
        ↓
페이지 폴트 발생 → CPU 이용률 낮아짐
        ↓
운영체제: "CPU가 한가한가?" → 더 많은 프로세스를 메모리에 올림
        ↓
다시 스와핑 증가... 🔄 (악순환)

→ 페이지 폴트가 너무 자주 발생해서 CPU가 실제 연산을 못하게 되는 상황

스레싱 해결 방법

① 작업 세트 (working set)

"자주 쓸 페이지를 미리 RAM에 올려놓자" → "예방"

프로세스의 과거 사용 이력인 지역성(locality)을 통해 결정된 페이지 집합을 만들어서 미리 메모리에 로드하는 방법
미리 메모리에 로드하면 탐색에 드는 비용을 줄일 수 있고 스와핑 또한 줄일 수 있음
미리 RAM에 올려둠
    ↓
페이지 폴트 자체가 안 발생
    ↓
스와핑 횟수 감소 → 스레싱 완화 ✅

② PFF (Page Fault Frequency)

"페이지 폴트 빈도 자체를 직접 조절하자" → "실시간 모니터링 및 조절"

페이지 폴트 빈도를 조절하는 방법으로 상한선하한선을 만드는 방법
상한선에 도달하면 프레임을 늘리고, 하한선에 도달하면 프레임을 줄임
페이지 폴트율이 상한선 초과
    ↓ 프레임 수 늘림
해당 프로세스에 RAM 더 할당
    ↓
페이지 폴트 감소 ✅
페이지 폴트율이 하한선 미달
    ↓ 프레임 수 줄임
RAM을 다른 프로세스에 양보
    ↓
전체 메모리 효율 증가 ✅

③ 메모리를 늘림

"근본적인 원인인 메모리 부족 자체를 해결하자" → 가장 직접적이고 비용이 드는 물리적 해결책

RAM 부족
    ↓
여러 프로세스가 RAM 자리를 두고 경쟁
    ↓
페이지 폴트 폭발 → 스레싱

RAM을 늘리면
    ↓
모든 프로세스가 충분한 프레임 확보
    ↓
페이지 폴트 자체가 줄어듦 ✅

 

④ HDD를 SDD로 바꿈

"스와핑 자체는 피할 수 없다면, 스와핑 속도를 빠르게 하자"

HDD 스와핑 속도: 매우 느림 🐢
    ↓
페이지 폴트 발생 시 HDD에서 가져오는 데 오래 걸림
    ↓
CPU가 오래 대기 → 이용률 급감 → 스레싱 심화
────────────────────────────────────────────
SSD로 교체하면
    ↓
스와핑 속도가 훨씬 빨라짐
    ↓
페이지 폴트 처리 시간 단축
    ↓
CPU 대기 시간 감소 → 스레싱 완화 ✅

2.2.3 메모리 할당

메모리에 프로그램을 할당할 때는 시작 메모리 위치, 메모리의 할당 크기를 기반으로 할당
연속 할당과 불연속 할당으로 나뉨

연속 할당

메모리에 '연속적으로' 공간을 할당하는 것

① 고정 분할 방식 (Fixed Partition Allocation)

  • 메모리를 미리 나누어 관리하는 방식
  • 융통성 없음
  • 내부 단편화 발생

② 가변 분할 방식 (Variable Partition Allocation)

  • 매 시점 프로그램의 크기에 맞게 동적으로 메모리를 나눠 사용
  • 외부 단편화 발생 가능
방식 설명
최초 적합 (First Fit) 위쪽이나 아래쪽부터 시작해서 홀을 찾으면 바로 할당
최적 적합 (Best Fit) 프로세스의 크기 이상인 공간 중 가장 작은 홀부터 할당
최악 적합 (Worst Fit) 프로세스의 크기와 가장 많이 차이나는 홀에 할당

단편화 용어 정리

용어 설명
내부 단편화
(Internal Fragmentation)
메모리를 나눈 크기보다 프로그램이 작아서 들어가지 못하는 공간이 많이 발생하는 현상
외부 단편화
(External Fragmentation)
메모리를 나눈 크기보다 프로그램이 커서 들어가지 못하는 현상
ex) 100MB를 55MB, 45MB로 나눴지만 프로그램이 70MB일 때
홀 (Hole) 할당할 수 있는 비어 있는 메모리 공간

불연속할당

메모리를 연속적으로 할당하지 않는 현대 운영체제가 쓰는 방법

① 페이징 (Paging)

동일한 크기의 페이지 단위로 나누어 메모리의 서로 다른 위치(RAM의 빈 프레임 아무 곳에나)에 프로세스를 할당
홀의 크기가 균일하지 않은 문제가 없어지지만 주소 변환이 복잡해짐

💡주소 변환이 복잡해지는 이유 : 페이징이 주소 변환이 복잡한 이유는 프로세스가 연속된 공간이 아닌 흩어진 프레임에 저장되기 때문에, CPU가 데이터에 접근할 때마다 "이 페이지가 RAM의 어느 프레임에 있는지"를 페이지 테이블에서 반드시 조회해야 하기 때문

→ 조회 비용을 줄이기 위해 TLB(주소 변환 캐시) 등장

② 세그멘테이션 (Segmentation)

페이지 단위가 아닌 의미 단위인 세그먼트(Segment)로 나누는 방식
프로세스를 이루는 메모리는 코드 영역, 데이터 영역, 스택 영역, 힙 영역으로 이루어지는데, 코드와 데이터로 나누거나 코드 내의 작은 함수를 세그먼트로 나눌 수도 있음
공유와 보안 측면에서 장점을 가지지만 홀 크기가 균일하지 않은 단점이 있음

③ 페이지 세그멘테이션 (Page Segmentation)

프로그램을 의미 단위인 세그먼트로 나눠 공유나 보안 측면에서 장점을 두고, 임의의 길이가 아닌 동일한 크기의 페이지 단위로 나누는 것

2.2.4 페이지 교체 알고리즘

메모리는 한정되어 있기 때문에 스와핑이 자주 발생
스와핑은 많이 일어나지 않도록 설계되어야 하며, 이는 페이지 교체 알고리즘을 기반으로 함
알고리즘 설명 특징
오프라인 알고리즘 먼 미래에 참조되는 페이지와 현재 할당하는 페이지를
바꾸는 방법
가장 좋지만 미래를 알 수 없어 사용 불가
다른 알고리즘의 상한기준 (upper_bound)제공
FIFO 가장 먼저 온 페이지를 교체 영역에 가장 먼저 놓는 방법 구현 단순
자주 쓰는 페이지도 오래됐다는 이유로 교체될 수 있음
LRU 참조가 가장 오래된 페이지를 바꿈 각 페이지마다 계수기, 스택을 두어야하는 문제점 존재
NUR
(clock 알고리즘)
0과 1의 비트를 두고 시계 방향으로 돌면서0을 찾아
교체하고 1로 바꿈 
LRU에서 발전한 방식
LFU 가장 참조 횟수가 적은 페이지를 교체 많이 사용되지 않은 것을 교체

LRU 구현 방법

LRU를 프로그래밍으로 구현할 때는 보통 해시 테이블 + 이중 연결 리스트 두 개의 자료구조로 구현

자료구조 역할
해시 테이블 이중 연결 리스트에서 특정 페이지를 O(1) 에 빠르게 찾을 수 있도록
이중 연결 리스트 한정된 메모리를 나타냄. 가장 최근에 사용된 순서 유지