프로그램은 윈도위의
*.exe
, mac의*.dmg
파일과 같이 컴퓨터에서 실행할 수 있는 파일 을 말한다. 파일을 실행하지 않은 상태인 정적 프로그램을 보통프로그램
이라고 한다
프로세스는 정적인 프로그램을 동작 시켜 프로그램이 돌아가고 있는 상태를 의미한다. 즉, 컴퓨터에서 작업 중인 프로그램을 프로세스라고 한다.
🚢 프로세스 :
🚣 스레드 :
✔ 요약
: 프로세스는 독립된 실행 환경을 가지고 있는 반면 스레드는 프로세스 내에서 실행되는 작은 실행 단위로 자원을 공유
👨💻👨👧👧🗂예를 들어, 한 개의 크롬 브라우저를 켜서 여러 텝을 통해 웹서핑, 온라인 쇼핑 결제, 웹 디스코드 화상미팅을 동시에 할 수 있는 이유가 여러 가지의 작업들의 흐름이 다중의 스레드를 통해 이뤄지기 때문이다.
Code (코드): 프로그램의 명령어들이 저장되는 영역이다. 실행 가능한 명령어들(CPU가 해석 가능한 기계어 형태)로 구성되어 있다.
Data (데이터): 전역 변수와 정적 변수 등의 데이터가 저장되는 영역이다. 프로그램의 초기화된 데이터들이 위치한다.
데이터 영역은 프로세스의 실행 시작 시 메모리에 할당되며, 컴파일 타임에 할당되는 영역이기 때문에 크기가 정적으로 결정된다. 또한, 데이터 영역은 프로세스의 다른 영역인 코드(Code), 스택(Stack), 힙(Heap)과는 별도로 관리되며, 프로세스의 수명 동안 메모리에 고정된 위치에 상주합니다.
데이터영역은 .data ,.rodata, .bss 영역으로 세분화된 섹션으로 구성될 수 있음.
1) .data 섹션 (Initialized Data Section):
.data 섹션은 초기화된 전역 변수와 정적 변수의 데이터를 저장하는 영역이다. 프로그램이 실행되기 전에 이미 초기화된 값들이 들어간다. 이 섹션은 실행 파일의 이미지에 실제로 데이터 값을 포함하고 있으며, 프로그램이 실행 중에 해당 데이터에 접근할 수 있다. 일반적으로 전역 변수와 정적 변수가 .data 섹션에 할당된다.
2) .bss 섹션 (Uninitialized Data Section):
.bss 섹션은 초기화되지 않은 전역 변수와 정적 변수의 데이터를 저장하는 영역이다. 이 섹션에는 값이 할당되지 않은 변수들이 위치하며, 실행 파일의 이미지에는 실제 데이터 값이 포함되지 않는다. 대신 프로그램이 실행될 때 변수들은 자동으로 0 또는 null로 초기화된다. 이렇게 초기화되지 않은 데이터의 크기만을 저장해둔다고 생각할 수 있다.
3) .rodata 섹션 (Read-Only Data Section):
.rodata 섹션은 읽기 전용 데이터를 저장하는 영역이다. 이 섹션에는 프로그램 내에서 사용되는 상수, 문자열 리터럴 등이 저장된다. .rodata 섹션의 데이터는 실행 중에 수정되지 않으며, 읽기만 가능하다. 일반적으로 문자열 상수와 같은 읽기 전용 데이터가 .rodata 섹션에 할당된다.
요약하자면, 데이터 영역은 전역 변수, 정적 변수, 상수와 같은 프로그램의 데이터를 저장하고 관리하는 영역이다.
Stack (스택): 함수 호출과 로컬 변수들이 저장되는 영역이다. 함수가 호출될 때마다 스택 프레임이 생성되고, 함수의 실행이 끝나면 해당 스택 프레임이 제거됩니다. 스택은 후입선출 (LIFO) 구조로 동작합니다. stack 영역을 초과하면 stack overflow 에러가 발생한다.
Heap (힙): 동적으로 할당된 메모리를 관리하는 영역이다. 프로그램 실행 중에 동적으로 메모리를 할당하고 해제하는 데 사용된다. 주로 동적으로 생성된 객체, 배열 등이 힙에 저장된다. 힙은 런타임에 메모리가 동적으로 할당되므로 크기가 동적으로 변경될 수 있다.
1) 동적 메모리 할당: 힙 영역은 프로그램 실행 중에 동적으로 메모리를 할당하는 데 사용된다. 동적 메모리 할당은 프로그램에서 필요에 따라 메모리 공간을 동적으로 확보하는 방법으로, malloc(), calloc(), realloc()과 같은 함수를 사용하여 할당된다.
2) 할당과 해제: 힙 영역에서는 메모리 블록을 할당하고 사용한 뒤, 더 이상 필요하지 않을 때 메모리를 해제해야 한다. 메모리 누수를 방지하기 위해 할당된 메모리를 적절히 해제해야 한다. 일반적으로는 free() 함수를 사용하여 할당된 메모리를 해제한다.
3) 크기의 동적 변경: 힙 영역에서는 동적으로 할당된 메모리의 크기를 변경할 수도 있다. realloc() 함수를 사용하여 메모리 블록의 크기를 재조정할 수 있다. 이를 통해 메모리의 크기를 늘리거나 줄일 수 있다.
4) 메모리 관리: 힙 영역에서는 메모리 관리를 위해 메모리 할당과 해제를 적절히 관리해야 한다. 이는 프로그래머의 책임이며, 잘못된 메모리 관리는 메모리 누수(memory leak)나 덮어쓰기(overwrite) 등의 문제를 초래할 수 있다.
프로세스는 위와 같은 자원들로 구성되어 있으며, 각 영역은 프로세스 메모리 공간에서 서로 다른 위치를 차지한다. 이러한 자원 구조를 효율적으로 활용하여 프로세스는 작업을 수행하고 필요한 데이터와 메모리를 관리한다.
스레드가 여러 개 있어서 우리는 웹 브라우저를 통해 웹 서핑과 동시에 파일 다운로드가 가능하게 된다. 스레드끼리 프로세스의 자원을 공유하면서 프로세스 실행 흐름의 일부가 되기 때문에 동시 작업이 가능하다.
스레드의 자원 공유는 동시에 여러 스레드가 동일한 데이터나 리소스에 접근하면서 문제가 발생할 수 있다. 이를 해결하기 위해 스레드 간의 자원 공유는 아래와 같은 개념들을 활용한다.
경쟁 상태 (Race Condition): 경쟁 상태는 여러 스레드가 동시에 자원에 접근하고 변경하려는 경우 발생하는 문제다. 예를 들어, 한 스레드가 값을 변경하고 있는 동안 다른 스레드가 동일한 값을 읽을 경우 예측할 수 없는 결과가 발생할 수 있다.
상호 배제 (Mutual Exclusion): 상호 배제는 동시에 여러 스레드가 자원에 접근하지 못하도록 하는 메커니즘이다. 상호 배제를 통해 한 번에 하나의 스레드만 자원에 접근할 수 있도록 제어한다. 이를 통해 경쟁 상태를 예방하고 자원의 일관성을 유지할 수 있다.
임계 영역 (Critical Section): 임계 영역은 상호 배제를 적용해야 하는 코드 영역을 의미한다. 임계 영역에 진입하기 위해서는 락(lock) 또는 세마포어 등의 동기화 메커니즘을 사용하여 다른 스레드가 접근하지 못하도록 한다.
동기화 (Synchronization): 동기화는 스레드 간에 작업을 조율하고 순서를 제어하는 메커니즘이다. 동기화를 통해 스레드가 올바른 순서로 작업을 수행하도록 하고, 상호 배제를 통해 자원에 대한 안전한 접근을 보장한다.