프로세스란?
컴퓨터에서 실행 중인 하나의 프로그램을 의미하며 프로그램이 실행되는 과정은 아래와 같다.
- 디스크에 있는 프로그램이 운영 체제에 의해 메모리에 로드됨 - > 인스턴스화
- 메모리 관리 장치에 의해 할당된 메모리 공간으로 바이너리 실행 코드가 올라감 -> 프로세스화
(※ 프로세스에는 프로세스 ID와 같은 프로그램이 실행되는 데 필요한 모든 정보를 포함한다.) - CPU에 의해서 프로세스가 실행되며 CPU 스케줄러에 따라 프로세스에 포함된 명령어들을 수행한다.
프로세스의 메모리 영역
프로세스는 프로그램의 코드를 실행하기 위해 필요한 RAM의 메모리 공간을 할당받으며 다음과 같이 분류된다.
- Code 영역
실행할 프로그램의 코드(명령어)가 기계어 형태로 저장되는 영역 - Data 영역
코드에서 선언한 전역 변수와 정적 변수가 저장되는 영역 (※ 프로그램이 실행되면서 할당되고 종료되면서 소멸) - Stack 영역(LIFO : Last In First Out)
함수 안에서 선언된 지역변수, 매개변수, 리턴값이 저장되는 영역 (※ 함수 호출 시 기록되고 종료되면 제거된다.) - Heap 영역(FIFO : First In First Out)
생성자, 인트선스와 같은 동적으로 할당되는 데이터를 위해 존재하는 영역
(※ 프로그래머가 직접 생성 및 관리한다.) - 정적 할당 & 동적 할당
데이터 & 코드 → 정적 할당(컴파일 단계에서 메모리를 할당하는 것을 의미).
스택 & 힙 → 동적 할당(런타임 단계에서 메모리를 할당하는 것을 의미)
항목 | 정적할당 | 동적할당 |
메모리 할당/해제 | 필요하지 않음 | 필요함 |
메모리 누수 발생 가능성 | 낮음 | 높음 |
메모리 사용량 예측 | 용이함 | 어려움 |
메모리 효율성 | 떨어짐 | 높을 수 이있음 |
※ 메모리 영역 공유에 발생하는 문제
오버 플로 : 메모리 공간에서 할당할 수 있는 최대 범위를 넘어가는 것
언더 플로 : 메모리 공간에서 할당할 수 있는 최소 범위보다 작은 것
스택 오버플로 : 스택 영역이 힙 영역을 침법
힙 오버플로 : 힙 영역이 스택 영역을 침범하는 경우
메모리 관리
다수의 프로세스를 실행하려면 한정된 메모리 공간에 많은 프로세스를 로드할 수 있어야 한다.
따라서 메모리 공간을 효율적으로 활용하기 위한 여러 방안이 고안되었다.
- 페이징
프로세스가 할당받은 논리 메모리 영역 -> 페이지,
PC가 가지고 있는 RAM 전체 물리 메모리 영역 -> 프레임
페이지와 프레임의 크기가 서로 동일하게 잘게 나눈다.
페이지와 프레임에 각각 번호를 할당하고 서로 매핑한다. - 요구 페이징
프로세스에서 필요한 페이지만 메모리에 로드하는 방식이다. 필요하지 않은 페이지는 디스크에 저장한다.
관리는 간단해지지만 페이지 폴트가 발생할 수 있어 오히려 프로세스의 실행 속도는 느려진다. - 페이지 폴트
프로세스가 메모리에 없는 데이터에 접근하려고 할 때 발생하는 오류이다.
프로세스가 처음 실행될 때, 프로세스가 실행되는 동안 페이지 폴트가 발생한다.
페이지 폴트가 발생하면 디스크에서 필요한 페이지를 스왑 인한다.
페이지 폴트를 줄이는 방법은 프로세스가 필요로 하는 데이터만 메모리에 로드하는 요구 페이징을 사용한다. (B) 프로세스가 메모리에 없는 데이터에 접근하지 못하도록 보호 메커니즘을 사용 - 세그먼테이션
프로세스의 메모리 영역을 논리적 단위인 세그먼트로 분할해 메모리를 할당한다. - 가상 메모리
프로세스의 일부만 메모리에 로드하고, 나머지는 디스크에 둔 상태로 프로세스를 실행하는 방법
이를 통해 더 많은 프로세스를 메모리에 로드할 수 있다. - 스레싱
동시에 일정 수 이상의 프로그램을 실행했을 때 오히려 CPU 이용률이 떨어지는 상황
※ 논리 메모리 영역 : 프로세스가 할당 받은 메모리 공간(e.g. 4GB)
※ 물리 메모리 영역 : 프로스세에게 메모리를 공간을 할당한 RAM(e.g. 16GB, 32GB 등..)
프로세스의 상태도
- 생성(new)
프로세스가 생성되어 PCB를 가지고 있지만 OS로부터 승인 받기 전 - 준비(ready)
OS로부터 승인받은 후 준비 큐에서 CPU 할당을 기다림 - 실행(running)
프로세스가 CPU를 할당받아 실행함 - 대기(waitting)
프로세스가 입출력이나 이벤트 발생을 기다려야 해서 CPU 사용을 멈추고 기다림 - 종료(terminated)
프로세스 실행을 종료함
스레드
사람이 초능력을 사용해 뇌를 여러개로 만들어서 하나의 작업을 여러개의 뇌로 동시에 처리하는 것과 비슷하다.
결국 같은 사람이기 때문에 서로 자원을 공유하게 되지만 스택 영역에는 추가적으로 스레드의 실행 흐름을 저장하는 데 사용되어 다른 스레드가 실행 상태를 변경할 수 있기 때문에 서로 공유하지 않는다.
PCB (Process Control Block)
운영체제에서 프로세스에 대한 메타데이터를 저장한 ‘데이터’를 의미
(※ 메타데이터 : 데이터를 설명하는 작은 데이터)
PCB의 구조
프로세스 상태 | ‘준비’, ‘일시중단’ 등 프로세스가 CPU에 대한 소유권을 얻은 이후의 상태 |
프로세스 ID(PID) | 해당 프로세스의 ID, 자식 프로세스의 ID |
프로세스 권한 | 컴퓨터 자원 또는 I/O 디바이스에 대한 권한 정보 |
프로그램 카운터(PC) | 프로세스에서 실행해야 할 다음 명령어의 주소에 대한 포인터 |
cpu 레지스터 | 프로세스를 실행하기 위해 저장해야 할 레지스터에 대한 정보 |
cpu 스케줄링 정보 | cpu 스케줄러에 의해 중단된 시간 등에 대한 정보 |
계정 정보 | 프로세스 실행에 사용된 cpu 사용량, 실행한 유저의 정보 |
I/O 상태 정보 | 프로세스에 할당된 I/O 디바이스 목록 |
프로세스의 생성
기존 프로세스에서 fork() 함수를 호출하면 호출한 프로세스를 복사한 새로운 프로세스가 만들어지며
이 둘은 부모 - 자식 관계가 된다. fork의 반환값은 아래와 같다.
컨텍스트 스위칭(context switching)
A 프로세스를 CPU에서 처리하고 있었는데 이를 중단하고 인터럽트로 인해 발생한 B 프로세스를 처리해야 할 때
즉, A 프로세스 -> B 프로세스 전환 과정을 컨텍스트 스위칭이라고 한다.
CPU가 멀티 코어일 경우에는 B 프로세스를 다른 코어에서 실행하면 되겠지만 싱글코어일 경우 컨택스트 스위칭을 통해 프로그램을 실행시켜야 하고 이로 인해 캐시미스가 발생할 수 있다. (※ 캐시미스 - 유휴시간)
인터럽트(Interrupt)
프로그램 실행 도중에 얘기치 않은 상황이 발생하여 실행중인 작업을 중단하고 발생된 상황을 처리한 후 다시 실행중인 작업으로 복귀하는 것을 의미
(※ 크게 외부 인터럽트, 내부 인터럽트, 소프트웨어 인터럽트 3가지가 있다.)
인터럽트 동작 순서
- 인터럽트 발생 (IRQ : Interrupt Request)
- 프로그램 실행 중단 : 실행중이던 Micro operation 동작 까지만 수행
- 현재의 프로그램 상태 보존 : PCB(Process Control Block), PC(Program Counter) 등
- 인터럽트 처리루틴 실행 : 인터럽트 요청한 장치 식별
- 인터럽트 서비스 루틴 실행 : 인터럽트 원인 파악 및 실질적 작업 수행 → 인터럽트 발생 시 처리 코드(ISR) 동작
- 상태 복구 : 인터럽트 발생 시 저장해준 PC(Program counter) 상태 복구
- 중단된 프로그램 실행 재개 : 이전에 수행중이던 프로그램을 재개
프로세스 동기화
- 경쟁 상태
여러 프로세스 또는 스레드가 하나의 데이터베이스에 동시에 접근하여 데이터를 수정하면 경쟁 상태가 되며
오류가 발생할 수 있어 프로세스 동기화가 필요하다.
(하나의 게임 케릭터에 동시에 접속하면 에러가 발생하듯이..) - 교착 상태
프로세스 또는 스레드가 서로의 자원을 기다리면서 영원히 진행되지 못하는 상태 - 임계 영역
경쟁 상태가 되어 데이터의 일관성을 깨드릴 수 있는 코드 영역(프로그램이 실행되는 부분)을 임계 영역이라고 한다. - 뮤텍스
mutex = Lock() 선언을 통해 공유 자원을 사용하지 못하도록 잠그고 사용을 해야하는 프로세스 에서 뮤텍스 잠금을
mutex.acquire() 선언을 통해 해제하는 프로세스 동기화 방법이다.
바쁜 대기(busy waiting) 프로세스가 공유 자원에 접근할 수 있는 권한을 얻을 때까지 확인하는 과정이며
스핀락(spin lock)은 락을 얻기 위해 프로세스가 반복문을 돌면서 기다리는 상태이다.
(※ 공유 자원에 대한 독점적인 접근을 보장한다.) - 세마포어
동기화 운영체제 기술을 사용하여 공유 자원에 접근할 수 있는 프로세스의 수를 정해 접근을 제어하는 방법이다.
(※ 공유 자원에 대한 접근을 제한, 공유 자원에 대한 독점적인 접근 보장, 경쟁 상태 방지, 공유 자원의 일관성 유지)
* P 연산 : 세마포어 값을 감소시킴 (0보다 작은 경우 프로세스 또는 스레드는 대기 상태로 전환됨)
* V 연산 : 세마포어 값을 증가시킴 - 스왑 아웃
RAM이 부족해 프로세스를 저장공간에 옮겨 저장하는 것 - 스왑 인
다시 RAM에 로드하는 것 - 스와핑
프로세스를 통째로 메모리 영역과 저장 공간으로 옮기는 것을 스와핑이라고 한다.
특성 | 뮤텍스 (Mutex) | 세마포어 (Semaphore) |
값의 범위 | 이진 (0 또는 1) | 정수 (0 이상) |
주요 용도 | 상호 배제 및 스레드 동기화 | 다양한 동기화 문제 해결 |
초기화 및 활성화 | 뮤텍스는 초기화 및 잠금 연산만 있음 | 세마포어는 초기화, P(대기) 및 V(릴리스) 연산이 있음 |
사용법 | 단일 스레드 또는 멀티 스레드 환경에서 사용 가능 | 멀티 스레드 환경에서 주로 사용 |
교착 상태 방지 | 뮤텍스는 단순한 상호 배제에 사용되며 교착 상태 방지 기능 없음 | 세마포어를 적절히 사용하여 교착 상태 방지 가능 |
동작 방식 | Lock 및 Unlock 연산만 존재 | P(대기) 및 V(릴리스) 연산을 사용하여 다양한 상황을 다룸 |
값 변화 방식 | 값이 0 또는 1로 유지되며 상호 배제 상황을 나타냄 | 값을 0 이상의 정수로 유지하며, 리소스의 가용성을 나타냄 |
DMA 컨트롤러
기본적인 입출력 제어 방식(Polling) 예를 들어 하드디스크 에서 데이터를 꺼낼때 하드 → CPU 레지스터 → 메모리로 옮겨지는 방식을 쓰는데 입출력 시간 동안 CPU는 계속 대기상태에 있어야 하여 처리할 게 많은 CPU 입장에서는 큰 낭비이다.
- DMA(Direct Memory Access, 직접 메모리 접근)
DMA는 I/O(하드디스크, 그래픽 카드 등)들이 메모리에 직접 접근하여 읽거나 쓸 수 있도록 하는 대부분의 AP(or MCU)에서 제공하는 기능이다. CPU는 제어 신호만 주고 받는 역할을 하며 기존 CPU가 하는 데이터 저장 및 전달을 DMA 컨트롤러가 대신하게 된다.
DMA 동작 순서
- 입출력 장치가 CPU에게 입출력 요청
- CPU가 DMA 컨트롤러에 명령 송신
- DMA가 CPU에게 시스템 버스 사용 요청
- CPU가 버스 사용 허가
- DMA 컨트롤러가 입출력장치에서 데이터 읽은 후 메모리로 전송
- 전송 완료 후 CPU에게 완료 신호 송신
프로그램의 컴파일 과정
1. 전처리
소스 코드의 주석을 제거하고 #include 등 헤더 파일을 병합하여 매크로를 치환한다.
2. 컴파일러
오류 처리, 코드 최적화 작업을 하며 어셈블리어를 변환
3. 어셈블러
목적 코드(object code)로 변환함, 리눅스에서는 .o
4. 링커
프로그램 내에 있는 라이브러리 함수 또는 다른 파일들과 목적 코드를 결합하여 실행 파일을 만든다.
(확장자는 .exe 또는 .out)
'cs기초' 카테고리의 다른 글
컴파일러 & 기타 (0) | 2023.08.10 |
---|---|
컴퓨터 & 운영체제 (0) | 2023.08.10 |
네트워크 (0) | 2023.08.10 |