목차
- 프로세스(Process)란?
- 프로세스의 종류
- 프로세스의 구조
- 정적 할당 vs 동적 할당
- 프로세스의 실행
- 프로세스의 상태
- 스레드(Thread)란?
- 멀티 프로세스와 멀티 스레드
- 프로세스 간 통신(IPC, Inter-Process Communication)
프로세스(Process)란?
프로세스는 운영체제로 부터 자원을 할당받는 작업의 단위이다.
프로세스가 실행되기 위해서는 CPU가 필요하다.
여러 프로세스는 번갈아가며 CPU를 할당받아 실행된다.
예를 들어 메이플과 카트라이더라는 두 개의 프로세스가 있다면,
두 프로세스는 번갈아가며 실행되면서 동시에 실행되는 거 처럼 보이게 한다.
(즉 CPU가 하나라면 매 순간은 하나의 게임만 돌아가고 있는 것이다. 이를 빠르게 왔다갔다하며 동시에 실행되는 거 처럼 보이게 하는 것.)
프로세스의 종류
- 포그라운드 프로세스(Foreground Process): 사용자가 보는 공간에서 상호작용하는 프로세스
- 백그라운드 프로세스(Background Process): 사용자가 보지 못 하는 곳에서 실행되는 프로세스
- 데몬: 사용자와 별다른 상호작용 없이 주어진 작업만 수행(윈도우에서는 이를 서비스라고 부름)하는 백그라운드 서비스
프그라운드 프로세스 vs 백그라운드 프로세스
브라우져, cmd 등 사용자의 입력을 받고 그것들을 처리하는 프로세스가 포그라운드 프로세스이다.
백업, 서비스 운영, 시스템 성능 유지, 보안등을 위해, 우리가 모르게 동작하고 있는 프로세스가 백그라운드 프로세스이다.
백그라운드 프로세스 vs데몬
사용자와 직접적으로 상호작용하지 않는 백그라운드 프로세스 중에서도 데몬은 주로 시스템 서비스와 관련된 지속적인 작업을 위해 실행된다.(시스템이 부팅될 때 시작되어, 장기적으로 서비스를 제공)
프로세스의 구조

프로세스 종류와 무관하게 구조는 동일하다.
프로세스를 구성하는 메모리 내의 정보는 다음과 같이 이뤄져있다.
커널 영역에는 PCB(Process Control Block)이라는 정보가 저장된다.
사용자 영역에는 프로세스의 코드, 데이터등이 스택, 힙, 데이터, 코드 영역에 저장된다.
- 커널 영역
- PCB(Process Control Block)
- 사용자 영역
- 스택 영역
- 힙 영역
- 데이터 영역
- BSS 영역
- 코드 영역(= 텍스트 영역)
PCB(Process Control Block)
운영체제는 여러 프로세스를 관리한다.
따라서 이 프로세스들을 구분하기 위한 정보를 가지고 있어야 하고,
이게 바로 PCB이다.
PCB란 프로세스와 관련된 다양한 정보를 내포하는 구조체이다.
프로세스가 메모리에 적재될 때(프로세스 생성), PCB가 커널 영역에 만들어지고 프로세스가 끝나면 폐기된다.
PCB에 담기는 정보들
- 프로세스 ID: 프로세스 식별 번호
- 실행 과정에서 사용한 레지스터 값
- 프로세스 상태: 현재 프로세스가 어떤 상태인지(실행 중, 대기 중, 준비 중, 종료등)
- CPU 스케줄링 정보: 언제 CPU를 할당받을 지
- 메모리 관련 정보: 프로세스의 메모리상 적재 위치
- 파일 및 입출력장치 관련 정보
위 PCB 정보는 프로세스 테이블에 저장된다.
프로세스 테이블
실행중인 PCB의 모음.
새롭게 실행되는 프로세스는 PCB가 프로세스 테이블에 저장되고, 종료되면 삭제된다.
만약 프로세스가 비정상 종료된다면, 프로세스 테이블에 PCB가 남아있을 수 있다.
이러한 비정상 종료 상태를 좀비 프로세스(zombie process)라고 한다.
사용자 영역
스택 영역
일시적으로 사용할 값들이 저장되는 공간.(매개변수, 지역변수, 함수 복귀 주소등이 저장된다.) 스택 영역에는 스택 트레이스 형태의 함수 호출 정보가 저장될 수 있다.
사용되고 바로 해제되는 정보들이 저장되므로 스택을 활용한다.
스택 트레이스: 특정 시점에 스택 영역에 저장된 호출된 메서드들의 순서와 위치정보
- 스택 트레이스 정보를 통해, 예외가 발생하였을 때 발생한 원인을 추적하고 디버깅할 수 있다.
java.lang.NullPointerException
at com.example.Example.myMethod(Example.java:13)
at com.example.Example.main(Example.java:6)
힙 영역
사용자가 직접 할당 가능한 공간.
반드시 다 사용한 공간은 반환해야 한다.(안하면 메모리 누수가 발생한다.)
자바는 가비지 컬렉션 기능을 통해 자동으로 힙 메모리를 해제한다.
데이터 영역
프로그램이 실행되는 동안 유지할 데이터가 저장되는 곳. 정적 변수나 전역 변수(초기값이 있는 데이터)를 저장
BSS 영역
초기값이 없는 전역 변수나 정적 변수를 저장
코드 영역(=텍스트 영역)
실행 가능 명령어가 저장되는 공간, 즉 텍스트가 저장됨. CPU가 읽고 실행할 명령어가 저장되어 있기에 쓰기가 금지되어 있고, 읽기 전용(read-only)공간이다.
정적 할당 영역 vs 동적 할당 영역
정적 할당 영역: 프로그램 실행 도중 크기가 변하지 않는 영역(코드 영역, 데이터 영역이 해당된다.)
동적 할당 영역: 크기가 변할 수 있는 영역(힙, 스택 영역이 해당된다.)
프로세스의 실행
메모리에 적재된 프로세스들은 모두 한번에 실행되지 않는다.
프로세스가 실행되기 위해서는 CPU가 필요하다. 따라서 CPU가 한 개라면 이 CPU를 프로세스들이 번갈아 사용하게 된다.
즉 프로세스가 실행된다는 말은 운영체제에 의해 CPU 자원을 할당받았다라는 말과 동일하다.
이렇게 순서대로 프로세스가 번갈아 실행되려면, CPU 사용 시간이 정해져야 한다.
CPU 사용 시간은 타이머 인터럽트(= 타임아웃 인터럽트)에 의해 제한된다.
프로세스는 정해진 시간만큼 CPU를 이용하고, 타이머 인터럽트가 발생하면 자신의 차례를 넘기고 다음 차례가 올 때까지 기다린다.
문맥(Context)
타이머 인터럽트에 의해 A라는 프로세스가 중단된다면 이 중간 정보(프로그램 카운터, 레지스터 값, 메모리 정보등)를 백업해야 한다.
그래야 다음 차례에 중간 지점부터 재개할 수 있기 때문이다.
프로세스의 수행을 재개하기 위해 기억해야 하는 정보를 문맥이라고 한다.
이 문맥정보는 PCB에 저장된다.
따라서 운영체제는 인터럽트가 발생하면 PCB에 문맥을 저장하고 뒤이어 실행할 프로세스의 문맥을 가져온다.
이 과정을 문맥 교환(Context Switching)이라고 한다.
잦은 문맥 교환으로 인한 캐시 미스
문맥 교환이 자주 일어나면 동시에 많은 프로세스를 실행할 수 있지만,
반대로 캐시 미스가 자주 발생하여 메모리에서 프로세스 정보를 자주 가져와야 되고 이는 오버헤드로 이어질 수 있다.
따라서 문맥 교환이 자주 일어난다고 좋은 것은 아니다.
프로세스의 상태

프로세스는 위와 같이 생성, 준비, 대기, 실행, 종료 상태를 가질 수 있다.
그리고 여러 상태로 변환되며 프로세스는 실행된다.
프로세스가 상태를 가지는 이유는 운영체제가 프로세스들에게 CPU를 제공할 지 판단하기 위해서이다.
프로세스의 상태
- 생성: 프로세스가 메모리에 적재되고 PCB를 할당받고 있는 상태. 즉 프로세스를 생성 중
- 준비: 생성이 끝나고, 당장이라도 CPU를 할당받을 수 있는 상태. 다만 자신의 차례가 아니라 기다리고 있는 상태. 이 때 준비 상태에서 실행 상태로 전환되는 것을 디스패치라 한다.
- 실행: CPU를 할당받아 실행중인 상태. 프로세스가 할당된 시간을 모두 사용하면 다시 준비 상태가 되고, 입출력 장치를 사용하여 이 작업이 끝날 때까지 기다리고 있으면 대기 상태로 간다.
- 대기: 입출력 작업을 요청한 것과 같이 당장 실행이 불가능한 조건에 놓인 경우. 입출력 작업이 완료되어 실행 가능해지면 준비 상태가 된다.
- 종료: 프로세스가 종료된 상태. 프로세스가
exit()
나 예외 상태등으로 종료되면, 운영체제가 이를 감지하여 종료 상태로 변경하고 사용한 메모리를 정리한다.
입출력 장치를 사용하게 되면 반드시 대기 상태로 들어갈까?
정답은 아니다.
입출력에는 블로킹 입출력, 논블로킹 입출력이 존재한다.
블로킹 입출력(blocking I/O)은 입출력 작업을 수행해야 하면 프로세스가 대기 상태로 들어가고, 작업이 끝나면 준비상태가 된다.
논블로킹 입출력(non-blocking I/O)은 입출력 작업을 수행해야 하면 입출력 작업을 맡기고, 곧바로 이어지는 명령어를 수행한다.
즉 논블로킹 입출력의 경우 대기 상태로 들어가지 않는다.
스레드(Thread)란?
스레드(Thread)는 프로세스 내에서 실행되는 가장 작은 실행 단위이다. 스레드는 프로세스가 할당받은 자원을 공유하며, 프로세스 내부에서 여러 작업을 동시에 수행할 수 있도록 해준다.
즉 한 CPU에 여러 프로세스가 번갈아 처리된 것과 유사하게,
한 프로세스 내의 작업들을 여러 스레드로 쪼개어 처리하면 더 효율적이고 빠르게 처리할 수 있게 된다.
예를 들어 한 서버(프로세스)가 존재한다면, 이 서버에 여러 요청이 동시에 올 수 있다.
이 때 각 요청을 각각의 스레드가 돌아가며 처리하면, 응답성이 향상된다.
또한 멀티코어 시스템(여러 CPU)에서는 여러 스레드를 병렬 처리할 수도 있다.
멀티 프로세스와 멀티 스레드
멀티 프로세스
하나의 프로그램이 여러 프로세스로 구성되어, 각 프로세스가 하나의 작업을 처리하는 것.
예를 들어 브라우져는 탭마다 다른 프로세스로 동작한다.
5개의 탭이 있으면 5개의 프로세스가 돌아간다.
멀티 프로세스를 사용하면 프로세스들이 자원을 공유하지 않고, 독립적으로 실행되기 때문에 한 프로세스에서 문제가 발생해도 다른 프로세스에 영향을 주지 않는다.
왜냐하면 프로세스별로 별도의 메모리 및 자원을 사용하기 때문이다.
멀티 스레드
한 프로세스를 구성하는 코드를 여러 스레드로 실행하는 방법을 멀티 스레드라고 한다.
각 스레드는 고유의 스레드 ID, 프로그램 커운터, 레지스터 값, 스택을 갖는다.
다만 멀티 프로세스와는 다르게 같은 프로세스 자원을 공유한다.
즉 동일한 주소 공간의 코드, 데이터, 힙 영역, 파일을 공유하기에
멀티 스레드 환경에서 한 스레드에 생긴 문제는 다른 스레드에도 영향을 미쳐 프로세스 전체의 문제가 될 수도 있다.
여기서 스레드가 공유 및 개인 소유하는 자원을 정리하면 다음과 같다.
스레드 개별 자원
- 스레드 ID
- 프로그램 카운터
- 레지스터 값
- 스택
스레드 공유자원
- 코드
- 데이터
- 힙
- 파일
즉 전역 변수등은 공유하고, 스택은 별도로 갖고 있기 때문에 스레드마다 다음 실행할 주소와 연산 과정 임시 값을 별도로 갖는다.
프로세스 간 통신(IPC, Inter-Process Communication)
멀티 스레드는 공유 자원을 통해 서로 정보를 주고 받을 수 있다.
하지만 프로세스는 자원을 공유하지 않기에 정보를 주고 받기 어렵다.
프로세스는 다음 두 가지 방법을 통해 정보를 주고 받는다.
- 공유 메모리
- 메시지 전달
1.공유 메모리
데이터를 주고받는 프로세스가 공통적으로 사용할 메모리 영역을 두는 것.
즉 프로세스 별로 할당된 메모리 외에, 추가적으로 공유 메모리를 두고 이 공간을 읽고 쓰면서 데이터를 공유한다.
다음과 같은 공유 메모리 방식이 존재한다.
- 시스템 콜을 활용
- 공유 변수, 파일을 활용
시스템 콜이란?
프로세스가 하드웨어에 직접 접근하지 않고, 운영체제에 시스템 콜이라는 요청을 통해 하드웨어를 사용하는 것.
이 때 프로그램이 커널모드로 들어간다.
공유 메모리 장단점
- 커널 모드를 거의 거치지 않아 빠르다.
- 데이터 일관성이 훼손될 수 있다.
공유 메모리 방식은 프로세스 끼리 메모리를 공유하는 방식이다.
이 때 프로세스들이 공유 메모리로 접근할 때는 시스템 콜을 활용한다.(즉 커널모드로 들어간다.)
다만 이렇게 한번 접근하면, 커널 모드 진입 없이 메모리에 직접 접근할 수 있게 되면서 읽기, 쓰기가 빨라진다.
단점으로 커널 모드를 거치지 않고, 직접 쓰므로 두 프로세스가 동시에 메모리에 쓸 수 있다. 그러므로 데이터 일관성이 훼손될 수 있다.
2.메시지 전달
프로세스 간의 메시지 형태로 데이터를 주고 받는 것.
이 때 메세지를 보내고 받는 것은 각각 send() , recv() 시스템 콜을 활용한다.
메시지 전달 장단점
- 일관성, 동기화 문제가 거의 없다.
- 상대적으로 느리다.
시스템 콜을 적극적으로 활용하는 방법이기에, 공유 메모리 방식에 비해 일관성, 동기화 문제가 많이 적다.
다만, 매번 커널 모드를 진입하므로 통신 속도는 상대적으로 느리다.
메시지 전달 수단
메시지 전달 수단으로는 다음과 같은 것들이 있다.
- 파이프
- 시그널
- 소켓
- 원격 프로시저 호출(RPC)
파이프
단방향 프로세스 간의 통신 도구이다.
단방향이므로 한 파이프에서 특정 입구는 쓰기만 가능하고 반대는 읽기만 가능하다.
따라서 두 프로세스가 쓰기, 읽기를 모두 하려면 두 개의 파이프가 필요하다.
시그널
시그널이란 프로세스에게 특정 이벤트가 발생했음을 알리는 비동기적인 신호이다.
시그널은 메시지 전달을 위해 존재하는 개념은 아니지만, 시그널을 통해 메시지 전달도 가능하다.
시그널은 여러 종류가 존재하고, 각 시그널을 일으킬 수 있는 이벤트도 다양하다.
프로세스는 시그널이 발생하면 하던 일을 중단하고, 시그널 처리를 위한 시그널 핸들러를 실행한 후 실행을 재개한다.
소켓
소켓이란 네트워크 상에서 두 프로세스가 데이터를 주고 받기 위한 엔드포인트이다.
두 프로세스가 소켓 연결을 통해 TCP/UDP 프로토콜등을 통해 메시지를 주고 받을 수 있다.
원격 프로시져 호출(RPC, Remote Procedure Call)
RPC란 네트워크를 통해 다른 프로세스(혹은 서버)의 함수를 호출하는 방법이다.
Restful API와 다르게, 직접 다른 프로세스의 함수를 그대로 호출한다.
이는 성능이 더 좋고, 지속적인 연결을 유지할 수 있기에 msa에서도 많이 쓰인다.(성능이 더 좋은 이유는 Restful API와 달리 http/2 프로토콜을 사용하기 때문이다.)
이 PRC 방식은 함수를 호출하여 매개변수에 메세지를 전달한다.
생각해 볼 질문
- 프로세스란?
- Context Switching이란?
- Context Switching을 많이 하면 좋을까?
- 멀티 프로세스와 멀티 스레드의 차이는?
- 멀티 스레드의 장단점은?
- 스레드가 공유하는 자원과 개별로 갖고 있는 자원은 어떤 것들이 있을까?
- 스레드는 왜 스택을 개별로 갖고 있을까?