작업 관리자를 열면 프로세스 목록이 보이고 개발 문서를 읽다 보면 스레드 얘기가 나옵니다. 둘 다 “실행되는 무언가”인 것 같은데, 정확히 뭐가 다른 걸까요.
기술면접에서 가장 자주 나오는 질문을 하나만 꼽으라면 단연 이겁니다. “프로세스와 스레드의 차이를 설명해 주세요.”
단골 질문인 이유는 간단해요. 이 하나로 메모리 구조, 운영체제, 동시성까지 줄줄이 확인할 수 있거든요.
이 글에서는 두 개념의 차이를 메모리 구조 관점에서 정리하고, 면접에서 어디까지 답하면 좋은지까지 다뤄볼게요.
핵심부터 정리하고 시작합니다.
- 프로세스(Process): 실행 중인 프로그램. 독립된 메모리 공간을 통째로 받는다
- 스레드(Thread): 프로세스 안의 실행 흐름. 스택만 따로 갖고 나머지는 공유한다
- 공유하니까 스레드는 가볍고 빠르지만, 공유하니까 데이터 레이스가 생긴다
- 프로세스는 격리되어 안전하지만, 그만큼 무겁고 통신이 번거롭다
프로세스: 실행 중인 프로그램
프로그램은 디스크에 저장된 코드 덩어리입니다. 아직 아무 일도 하지 않아요.
이 프로그램을 실행하는 순간, 운영체제가 메모리에 올리고 CPU를 배정할 준비를 합니다. 이 “실행 중인 프로그램”이 프로세스예요.
운영체제는 프로세스마다 독립된 가상 메모리 공간을 통째로 내어줍니다. 구조는 크게 네 구역이에요.
| 영역 | 담는 것 |
|---|---|
| 코드(Text) | 실행할 기계어 코드 |
| 데이터(Data) | 전역 변수, 정적 변수 |
| 힙(Heap) | 런타임에 동적으로 할당하는 메모리 |
| 스택(Stack) | 함수 호출 정보, 지역 변수 |
여기서 중요한 건 “독립”이라는 단어입니다. A 프로세스는 B 프로세스의 메모리를 들여다볼 수 없어요. 운영체제가 원천 차단합니다.
그래서 한 프로세스가 죽어도 다른 프로세스는 멀쩡합니다. 크롬이 탭마다 프로세스를 따로 띄우는 이유가 이거예요. 탭 하나가 뻗어도 브라우저 전체는 살아남죠.
스레드: 프로세스 안의 실행 흐름
스레드는 프로세스 안에서 실제로 코드를 실행하는 흐름 단위입니다. 모든 프로세스는 최소 한 개의 스레드(메인 스레드)를 갖고 시작해요.
핵심은 공유 범위입니다. 같은 프로세스 안의 스레드들은 코드·데이터·힙 영역을 공유하고 스택만 각자 따로 가져요.
스택을 따로 갖는 이유는 명확합니다. 스택은 “지금 어떤 함수를 어디까지 실행했나”의 기록이라서, 실행 흐름마다 하나씩 있어야 하거든요.
반대로 힙을 공유하는 덕분에 스레드끼리는 변수 하나로 바로 데이터를 주고받을 수 있습니다. 별도 통신 절차가 필요 없어요.
왜 스레드를 쓸까: 비용의 문제
“여러 일을 동시에 하고 싶으면 프로세스를 여러 개 띄우면 되지 않나?” 싶을 수 있는데, 비용이 문제입니다.
생성 비용. 프로세스를 만들려면 독립 메모리 공간을 통째로 준비해야 합니다. 스레드는 스택 하나만 추가하면 끝이에요.
전환 비용. CPU가 다른 프로세스로 넘어가려면 메모리 맵 전체를 갈아끼워야 합니다(컨텍스트 스위칭). 같은 프로세스 안의 스레드 전환은 훨씬 가볍습니다.
통신 비용. 프로세스끼리 데이터를 주고받으려면 파이프, 소켓 같은 IPC(프로세스 간 통신) 절차를 거쳐야 합니다. 스레드는 그냥 같은 변수를 읽으면 돼요.
정리하면, 스레드는 “가볍게 여러 일을 벌이기 위한” 단위입니다.
공짜는 아닙니다: 데이터 레이스
스레드의 장점은 전부 “메모리를 공유한다”에서 나오는데, 최대 약점도 정확히 같은 지점에서 나옵니다.
두 스레드가 같은 변수에 동시에 쓰기를 하면 결과를 예측할 수 없어요. 이게 데이터 레이스입니다.
count += 1 같은 한 줄짜리 코드도 내부적으로는 읽기 → 더하기 → 쓰기 세 단계라서, 두 스레드가 겹치면 증가가 사라지는 일이 실제로 벌어집니다.
그래서 락, 세마포어 같은 동기화 도구가 필요해지고 이걸 잘못 쓰면 데드락이라는 다른 지옥이 열립니다.
프로세스는 애초에 메모리가 격리되어 있으니 이런 문제가 없어요. 안전성과 효율의 트레이드오프인 셈입니다.
iOS 개발자 관점에서 보면
iOS에서는 앱 하나가 프로세스 하나입니다. 샌드박스 정책 때문에 앱이 다른 앱의 메모리에 접근할 수 없죠. 위에서 말한 프로세스 격리가 그대로 적용된 겁니다.
앱 안에서는 메인 스레드가 UI를 담당하고 네트워크나 무거운 연산은 다른 스레드로 보냅니다. “UI 업데이트는 메인 스레드에서”라는 규칙이 바로 스레드 개념 위에 서 있어요.
다만 요즘 iOS 개발에서 스레드를 직접 만드는 일은 드뭅니다. GCD의 큐나 Swift Concurrency의 Task에 작업을 던지면, 시스템이 스레드 풀에서 알아서 배정해요. 추상화 계층이 한 겹 올라갔을 뿐, 바닥에서 스레드가 돌고 있다는 사실은 변하지 않습니다.
면접에서는 이렇게
한 문장 답부터 시작하면 좋습니다.
“프로세스는 독립된 메모리 공간을 가진 실행 단위이고, 스레드는 프로세스 안에서 스택만 따로 갖고 나머지 메모리를 공유하는 실행 흐름입니다.”
그다음 꼬리 질문은 거의 정해져 있어요. “스레드가 뭘 공유하고 뭘 따로 갖나요?”(스택만 따로), “왜 스레드가 더 가볍나요?”(생성·전환·통신 비용), “공유하면 뭐가 문제인가요?”(데이터 레이스와 동기화)까지 이어지면 합격점입니다.
여기에 크롬 탭이나 iOS 샌드박스 같은 실제 사례를 하나 얹으면 암기가 아니라 이해라는 인상을 줄 수 있어요.
정리
- 프로세스는 실행 중인 프로그램이고, 운영체제로부터 독립된 메모리 공간(코드·데이터·힙·스택)을 받는다
- 스레드는 프로세스 안의 실행 흐름으로, 스택만 따로 갖고 코드·데이터·힙은 공유한다
- 스레드는 생성·전환·통신 비용이 싸서 가볍지만, 메모리 공유 때문에 데이터 레이스 위험이 있다
- 프로세스는 격리되어 안전하지만 무겁고, 통신에 IPC가 필요하다
- iOS에서 앱은 프로세스 하나이고, GCD·Task는 스레드 위의 추상화다
- 면접 답의 뼈대: 정의 한 문장 → 공유 범위 → 비용 차이 → 데이터 레이스
