프로세스
프로세스는 프로그램이 실행 중인 걸 의미한다. 아래의 이미지와 같이 우리가 평소에 사용하는 크롬, 카카오톡, 그림판, 엑셀 등 컴퓨터에서 실행하는 모든 파일을 프로그램이라고 부르며 프로그램을 실행하게 되면 그 프로그램은 프로세스로 메모리에 로드 된다. 예를 들어 한글 파일(.hwp)를 실행하면 해당 파일의 프로그램 코드와 실행에 필요한 데이터가 메모리에 할당된다. 이때 한글 프로그램은 독립적인 프로세스가 되어 CPU의 스케줄링 대상이 되며 실행된다.
프로세스는 아래와 같은 특징을 가진다.
- 각 프로세스는 자신만의 메모리 공간을 가지며 다른 프로세스와 메모리 공유를 하지 않아 서로 독립적으로 동작한다.
- 파일, 메모리, 네트워크 연결 등 시스템 리소스를 점유하고 관리한다.
- 프로세스 간 전환(Context Switching)은 CPU가 한 프로세스에서 다른 프로세스로 작업을 변경할 때 발생하며, 비교적 큰 오버헤드를 유발할 수 있다.
일반적으로 하나의 프로세스는 아래의 그림과 같은 자원 구조를 가지고 있다.
- TEXT 영역에는 실행할 프로그램 코드가 있으며, 읽기 전용으로 되어 있어 수정은 할 수 없다.
- DATA 영역에는 전역변수와 정적 변수가 저장되어 있고, 프로그램이 시작될때 할당되어 종료될 때까지 유지된다.
- Heap 영역과 Stack 영역은 동적 메모리이기 때문에 Free Space 라는 할당되어 있지 않은 메모리 공간에서 자유롭게 메모리를 가져다 쓴다. Heap은 우리가
new
와 같이 생성자, 인스턴스 등 메모리를 할당할 때 이영역을 사용하고 Stack은 함수 호출, 매개 변수, 로컬 변수 등이 저장된다.
일반적으로 프로세스는 위에서 정리한 것처럼 프로그램을 실행하면 생성되는 실행 단위를 말하지만, 사실 프로세스의 개념은 단순히 프로그램 하나를 실행하는 것보다는 더 넓은 범위를 가진다. 복잡한 프로그램이나 시스템에서는 하나의 프로그램이나 시스템이 여러 개의 프로세스를 생성하여 작업을 분할하고 병렬로 처리하기 때문이다. 이렇게 하나의 프로그램이 여러 프로세스를 생성하여 작업하는 것을 우리는 멀티 프로세스라고 말한다.
멀티 프로세스
멀티 프로세스는 하나의 프로그램 여러 개의 프로세스로 분리해서 병렬로 작업을 실행하는 방식을 말하며 이로인해 성능 향상, 작업처리 속도 등 여러가지 효과를 얻을 수 있다. 멀티 프로세스의 특징은 다음과 같다.
- 멀티 프로세스도 각 프로세스가 독립적인 메모리 공간을 사용하기 때문에 서로 간섭하지 않아 안정성이 높다라는 장점이 있지만 메모리 사용량이 증가할 수 있다.
- 각 프로세스가 독립적이기 때문에 데이터 공유를 위해서는 프로세스간의 통신(IPC, Inter-Process Communication)을 사용해야 한다.
멀티 프로세스를 쓰는 가장 큰 이유는 스레드와 달리 하나의 프로세스에서 문제가 발생해도 독립된 메모리 공간을 가지기 때문에 다른 프로세스에 영향을 미치지 않는다. 아래에서 다루겠지만, 멀티 스레드의 경우 모든 스레드가 하나의 메모리 공간을 공유하기 때문에 한 스레드에서 문제가 생기면 전체 어플리케이션이 다운될 위험이 있다.
프로세스 1
└── 메인 스레드 1
├── 서브 스레드 1-1
└── 서브 스레드 1-2
프로세스 2
└── 메인 스레드 2
├── 서브 스레드 2-1
└── 서브 스레드 2-2
프로세스 3
└── 메인 스레드 3
└── 서브 스레드 3-1
그래서 독립적인 작업을 병렬로 처리할 때는 멀티 프로세스가 유리하다. 예를 들어 대규모 데이터 처리 작업에서 사용하면 데이터를 여러 단위로 나누어 병렬로 처리할 수 있다.
스레드
스레드는 프로세스 내에서 실행되는 작업 단위를 말하며 하나의 프로그램이 여러 작업을 동시에 수행할 수 있도록 해주는 역활을 한다. 프로세스가 시작되면 가장 먼저 생성되는 기본 스레드를 메인 스레드(Main Thread)라고 한다. 모든 프로세스는 기본적으로 하나의 메인 스레드를 가지고 시작하고, 이 메인 스레드에서 필요에 따라 새로운 스레드를 추가로 생성한다. 메인 스레드는 프로그램을 시작하고 종료하는 책임을 갖는다. 만약 메인 스레드가 종료되면 생성된 서브 스레드가 아직 실행 중이더라도 전체 프로세스가 종료된다.
프로세스
└── 메인 스레드 (1개)
├── 서브 스레드 1
├── 서브 스레드 2
└── 서브 스레드 3
서브 스레드의 경우 프로세스 내에서 여러 작업을 동시에 처리해야 하는 경우가 많은데 예를 들어 유튜브에서 동영상을 재생하면서(스레드 +1), 자막을 보여주고 (스레드 +1), 댓글을 쓰기 위해 유저의 입력을 (스레드 +1) 받아야 한다고 가정 한다면 해당 작업을 동시에 처리하기 위해서는 여러 스레드가 필요하다.
또한 스레드는 프로세스 내에서 메모리와 자원을 공유하면서 독립적으로 실행되는 단위이기 때문에 여러 스레드들은 같은 프로세스 내에서 코드, 데이터, 힙 메모리 등을 공유하면서 각자의 작업을 수행하며 아래와 같은 특징을 가진다.
- 스레드는 같은 프로세스 내에서 동작하기 때문에 같은 메모리에 접근할 수 있어 통신이 빠르다는 장점이 있지만 모든 스레드가 공유된 메모리를 사용하기 때문에 동기화, 동시성 등의 문제가 발생할 수 있다.
- 각 스레드는 자신만의 스택 영역을 가지고, 스택에는 함수 호출 정보와 로컬 변수가 저장하고 있기 때문에 각 스레드는 독립적으로 실행될 수 있다.
- 스레드를 통해 프로그램이 동시에 여러 작업을 수행할 수 있으며 멀티코어 CPU 환경에서는 각 코어에서 스레드를 병렬로 실행할 수 있어 효율이 더 높다.
- 스레드는 프로세스보다 오버헤드가 작다.
위에서 언급한 스레드의 특징을 보면 여러 스레드를 사용하면 모든게 효율적으로 보이고, 많이 있으면 좋을 것처럼 보이지만 스레드를 사용할 때는 주의할 점이 있다. 여러 스레드가 같은 자원(변수, 메모리)에 동시 접근하면 데이터가 손상이나, 한 스레드에서 문제가 생기면 같은 프로세스 내의 다른 스레드에 영향을 미칠 수 있기 때문에 주의가 필요하다.
멀티 스레드
멀티 프로세스와 마찬가지로 스레드 또한 멀티 스레드가 있다. 하나의 프로세스 내에서 여러 개의 스레드(Thread)를 생성하여 동시에 작업을 수행하는 것을 멀티 스레드라고 부르며 특징은 다음과 같다.
- 스레드는 프로세스의 메모리를 공유하기 때문에 추가적인 메모리 할당이나 자원 할당이 필요하지 않아 CPU 자원을 보다 효율적으로 사용할 수 있다.
- 데이터 교환이 빠르지만 스레드의 특징에서 언급 했듯 데이터 동기화, 동시성 등 다양한 문제가 발생할 수 있으며, 한 스레드가 예외나 오류로 종료되면 전체 프로세스가 영향을 받을 수 있다.
멀티 스레드는 입출력 대기시간이 긴 작업이나 빠른 응답성, 실시간으로 받아서 처리해야 할때 유용한데, FPS게임을 예로 이동이나 공격할때마다 실시간으로 받아서 처리 할때 멀티 스레드를 사용하면 지연 없이 빠르게 반응할 수 있다. 그러나 멀티스레드는 기본적으로 동시성 특성을 가지고 있기 때문에 다양한 동시성 문제가 발생할 수 있다. (이 부분에 대해서는 다음 글을 참고)
프로세스와 스레드 생명 주기(Life Cycle)
프로세스와 스레드는 생성(New), 준비(Ready), 실행(Running), 대기(Waiting/Blocked), 종료(Terminated) 단계를 거치면서 관리되고 있다.
프로세스의 생명 주기는 다음과 같다.
- 생성 (New) : 프로세스가 생성되고 아직 준비가 되지 않은 상태
- 준비(Ready) : 프로세스가 메모리에 로드되어 CPU를 할당받기 위해 대기 중인 상태
- 실행 (Running) : CPU를 할당 받아 실제로 명령을 실행 중인 상태
- 대기 (Waiting/Blocked) : 프로세스가 입출력 요청 작업 등으로 인해 잠시 멈추고 대기 중인 상태
- 종료 (Terminated) : 프로세스가 실행을 완료하고 자원을 해제한 상태
그리고 스레드는 다음과 같은 생명 주기를 갖는다.
- 생성 (New): 스레드가 생성되고 아직 호출되지 않은 상태
- 준비 (Runnable): 스레드가 실행될 준비가 된 상태로, CPU 할당을 기다리고 있는 상태
- 실행 (Running): 스레드가 CPU를 할당받아 실제로 실행 중인 상태
- 대기 (Waiting/Blocked): 특정 조건이 만족되거나 I/O 작업이 완료될 때까지 대기하는 상태
- 종료 (Terminated): 스레드가 작업을 완료하고 종료된 상태
보다시피 스레드는 프로세스 내에서 실행되는 작은 단위이기 때문에 프로세스와 비슷한 생명 주기를 가지며 프로세스와 스레드 생명 주기 예를 들면 아래와 같다.
- 생성 (New)
- 프로세스: 사용자가 브라우저를 열어 유튜브에 접속한다.
- 스레드: 유튜브에서 동영상을 재생하면 여러 스레드가 생성된다 (예: 동영상 재생 스레드, 자막 처리 스레드, 댓글 입력 스레드 등)
- 준비 (Ready/Runnable)
- 프로세스: 브라우저가 유튜브 페이지를 메모리에 로드하고 CPU 할당을 대기한다.
- 스레드: 생성된 스레드들(예: 동영상, 자막, 댓글 스레드)은 각각의 작업을 시작하기 위해 CPU 할당을 대기한다.
- 실행 (Running)
- 프로세스: 브라우저가 유튜브 페이지를 표시하고 동영상을 재생하며 사용자 입력을 처리한다.
- 스레드:
- 동영상 스레드: 영상을 재생한다.
- 자막 스레드: 자막을 화면에 표시한다.
- 댓글 입력 스레드: 사용자의 댓글 입력을 실시간으로 처리한다.
- 대기 (Waiting/Blocked)
- 프로세스: 네트워크에서 동영상 데이터를 로딩하는 동안 프로세스가 대기 상태로 전환된다.
- 스레드:
- 동영상 스레드: 영상 데이터를 더 받아야 할 때 네트워크 대기 상태로 전환된다.
- 자막 스레드: 자막 파일이 로드되지 않으면 대기 상태에 들어간다.
- 종료 (Terminated)
- 프로세스: 사용자가 유튜브 탭을 닫거나 브라우저를 종료하면 프로세스가 종료된다.
- 스레드: 동영상 재생이 끝나거나 사용자가 동영상을 중지하면 관련된 스레드들이 종료된다. 브라우저를 닫으면 모든 스레드가 함께 종료된다.