Backend
home
⚙️

프로세스 vs 스레드, 그리고 컨텍스트 스위칭

태그
Computer Science
게시일
2026/05/13
최종 편집 일시
2026/05/13 10:25
1 more property

왜 이 글을 쓰는가

Spring은 요청마다 스레드를 하나씩 쓴다.
DB 커넥션 풀은 스레드 수를 기준으로 튜닝한다.
Spring WebFlux는 스레드를 최소화해서 성능을 끌어올린다.
이 모든 것의 전제가 되는 질문이 하나 있다.
"프로세스와 스레드가 정확히 뭐가 다른가?"
이 개념이 흐릿하면 멀티스레드 버그가 왜 생기는지, 컨텍스트 스위칭 비용이 왜 문제가 되는지 설명할 수 없다.

1. 프로세스란

프로세스는 실행 중인 프로그램이다.
프로그램은 디스크에 저장된 코드 파일이고, 그것을 OS가 메모리에 올려 실행하기 시작하면 프로세스가 된다.

프로세스의 메모리 구조

각 프로세스는 이 메모리 공간을 독립적으로 가진다.
프로세스 A는 프로세스 B의 메모리를 직접 읽거나 쓸 수 없다.
OS가 가상 메모리로 각 프로세스를 격리하기 때문이다.

프로세스가 가진 것

독립된 메모리 공간 (Code, Data, Heap, Stack)
프로세스 ID (PID)
열린 파일 디스크립터
자식 프로세스
CPU 레지스터 상태 (PC, SP 등)

2. 스레드란

스레드는 프로세스 안에서 실제로 실행되는 작업 단위다.
하나의 프로세스 안에 여러 스레드가 존재할 수 있다.

스레드가 공유하는 것 vs 독립적으로 가지는 것

구분
내용
공유
Code 영역, Data 영역, Heap 영역, 열린 파일
독립
Stack, 레지스터(PC, SP 등), 스레드 ID
스레드는 같은 프로세스 내 메모리를 공유한다.
이게 스레드의 장점이자 위험이다.

왜 스레드를 쓰는가

프로세스를 여러 개 만들면 각각 독립된 메모리가 필요하고, 프로세스 간 통신(IPC)도 복잡하다.
스레드는 메모리를 공유하므로 데이터를 주고받기 쉽고, 생성 비용도 훨씬 작다.

3. 프로세스 vs 스레드 비교

항목
프로세스
스레드
메모리
독립
공유 (Heap, Data, Code)
생성 비용
높음
낮음
통신 방법
IPC (파이프, 소켓 등)
공유 메모리 직접 접근
격리성
강함 (하나가 죽어도 다른 프로세스 영향 없음)
약함 (하나가 죽으면 프로세스 전체 위험)
컨텍스트 스위칭 비용
높음
낮음
예시
Chrome 탭마다 프로세스 분리
Spring 요청 처리 스레드

4. 컨텍스트 스위칭

CPU는 한 번에 하나의 작업만 처리한다.
하지만 우리는 여러 프로그램이 동시에 돌아가는 것처럼 느낀다.
이게 가능한 이유가 컨텍스트 스위칭(Context Switching) 이다.

컨텍스트 스위칭이란

OS 스케줄러가 CPU를 점유하는 작업을 빠르게 교체하는 것이다.
교체할 때 현재 작업의 상태(컨텍스트)를 저장하고, 다음 작업의 상태를 복원한다.

컨텍스트란 무엇인가

프로그램 카운터(PC), 스택 포인터(SP), 범용 레지스터 값 등
CPU가 작업을 재개하는 데 필요한 모든 상태 정보다.
이 정보는 PCB(Process Control Block) 또는 TCB(Thread Control Block) 에 저장된다.

컨텍스트 스위칭 비용

컨텍스트 스위칭은 공짜가 아니다.
레지스터 저장/복원 시간
캐시 무효화: CPU 캐시(L1, L2)에 올라와 있던 데이터가 날아감
TLB 플러시: 프로세스 전환 시 가상 주소 변환 캐시도 초기화
스레드 전환은 같은 프로세스 내에서 일어나므로 메모리 공간이 같다.
그래서 프로세스 전환보다 비용이 작다.

언제 컨텍스트 스위칭이 발생하는가

원인
설명
타임슬라이스 소진
OS가 할당한 CPU 시간이 끝남
I/O 대기
파일 읽기, 네트워크 응답 대기 등
sleep() 호출
스레드가 스스로 CPU 양보
인터럽트
하드웨어 신호로 OS가 개입
우선순위 선점
더 높은 우선순위 스레드 등장

5. 멀티프로세스 vs 멀티스레드

멀티프로세스

하나가 죽어도 다른 프로세스에 영향 없음
메모리 사용량이 많고 통신이 복잡
예: Chrome (탭마다 별도 프로세스로 격리)

멀티스레드

메모리 효율 높음, 통신 단순
하나의 스레드가 공유 데이터를 잘못 건드리면 전체 프로세스에 영향
동기화 문제 (Race Condition, Deadlock) 발생 가능
예: Spring의 Tomcat 스레드 풀

6. 실무 연결 — Spring과 스레드

Spring MVC의 Thread-per-Request 모델

Tomcat은 스레드 풀을 유지한다. 기본 최대 200개.
요청이 들어오면 풀에서 스레드를 꺼내 처리하고, 완료되면 반환한다.
문제: 스레드가 I/O 대기 중(DB 쿼리, 외부 API 호출)이면 CPU는 놀고 있는데 스레드는 점유 중이다.
스레드가 모두 소진되면 새 요청은 대기한다.

Spring WebFlux의 이벤트 루프 모델

I/O 대기 동안 스레드를 점유하지 않는다.
적은 스레드로 많은 요청을 처리할 수 있다.
컨텍스트 스위칭 비용도 줄어든다.
단점: 코드가 복잡해지고, 블로킹 코드가 섞이면 오히려 성능이 나빠진다.

DB 커넥션 풀 튜닝과의 연결

HikariCP 기본 설정에서 커넥션 풀 크기는 보통 CPU 코어 수 × 2 수준을 권장한다.
스레드가 200개여도 동시에 CPU를 쓸 수 있는 스레드는 코어 수만큼이고,
나머지는 컨텍스트 스위칭 대기 중이기 때문이다.

정리

개념
핵심
프로세스
독립된 메모리를 가진 실행 단위. 격리성 강함
스레드
프로세스 내 실행 단위. Heap/Data 공유, Stack 독립
컨텍스트 스위칭
CPU 점유 작업 교체. 레지스터 저장/복원 + 캐시 비용
프로세스 전환
메모리 공간 전환 포함, 비용 큼
스레드 전환
같은 메모리 공간, 비교적 비용 작음
Spring MVC
요청마다 스레드 1개. 스레드 수가 처리량 상한
Spring WebFlux
소수 스레드 + 이벤트 루프. I/O 대기 중 스레드 해방
다음 글에서는 OS의 I/O 모델(Blocking / Non-Blocking / Async)을 다룬다.
이 글에서 나온 "I/O 대기 중 스레드 점유"가 왜 문제인지, 그 해결책이 무엇인지 이어진다.