프로세스
프로세스는 실행 중인 오브젝트 코드를 말하는데 언제나 활성화 상태로 실행 중인 프로그램이다. 정확히는 오브젝트 코드를 넘어 데이터, 리소스, 상태, 가상화된 컴퓨터를 포함한다.
프로세스는 커널이 이해하는 실행 파일 포맷으로 만들어져 실행 가능한 오브젝트 코드로 부터 시작된다. 리눅스에서 가장 일반적인 실행 파일 포맷은 ELF(Executable and Linkable Format) 이다. 실행 파일은 여러 섹션으로 구성되는데, 섹션에는 메타데이터, 코드, 데이터 등이 들어 있다. 이 섹션은 오브젝트 코드가 담긴 바이트 배열이며 선형 메모리 공간에 적재된다.
가장 중요한 공통 섹션은 텍스트 섹션, 데이터 섹션, bss 섹션이다.
텍스트 섹션
텍스트 섹션에는 실행 가능한 코드나 상수, 변수와 같은 읽기 전용 데이터가 있으며, 읽기 전용과 실행 가능으로 표시된다.
데이터 섹션
데이터 섹션에는 정의된 값을 할당한 C 변수와 같은 초기화된 자료가 있으며, 일반적으로 읽고 쓰기가 가능하도록 표시된다.
bss 섹션
bss 섹션은 초기화되지 않은 전역 데이터를 포함한다. C 표준에 따르면 C 변수의 기본값은 보통 0이므로 디스크에 저장된 오브젝트 코드에 0을 저장할 필요가 없다. 그 대신 오브젝트 코드는 단순히 bss 섹션에 초기화되지 않은 변수 목록을 유지하며 커널은 메모리에 올라오는 시점에서 모든 값이 0인 페이지를 bss 섹션에 매핑할 수 있다. bss 섹션은 오로지 이 목적을 위해 최적화되어 있다.
커널은 동작 중인 모든 프로세스가 시스템 프로세서를 공유하도록 빈틈없고 투명하게 프로세스를 선점하고 스케줄링한다. 커널은 가상 메모리와 페이징 기법을 사용해서 프로세스(단일 선형 주소 공간을 가짐)마다 다른 주소 공간에서 동작하도록 만들기 때문에 여러 프로세스가 시스템 상에 공존할 수 있는 것이다.
스레드
각 프로세스는 실행 스레드를 하나 이상 포함한다. 스레드는 프로세스 내부에서 실행하는 활동 단위이며, 코드를 실행하고 프로세스 동작 상태를 유지하는 추상 개념이다.
스레드는 스택, 프로세서 상태, 오브젝트 코드의 현재 위치를 포함한다. 이외의 대부분의 리소스는 모든 스레드가 공유한다. 이러한 방식으로 스레드는 가상 메모리를 공유하고 가상 프로세서를 관리한다.
프로세스의 계층 구조
각각의 프로세스는 pid(프로세스 ID) 라고 하는 고유한 양수 값으로 구분된다. 첫 번째 프로세스의 pid는 1 이다.
리눅스에서 프로세스는 프로세스 트리라는 엄격한 계층 구조를 형성한다. 일반적으로 프로세스 트리는 init 프로그램으로 알려진 첫 번째 프로세스가 루트가 된다. 새로운 프로세스는 fork() 시스템 콜로 만들어 지며, 호출하는 프로세스를 복사해서 다른 프로세스를 새로 만든다. 부모 프로세스가 자식 프로세스보다 먼저 종료되면 커널은 고아가 된 자식 프로세스를 init 프로세스에 입양시킨다.
프로세스가 종료되면 시스템에서 바로 제거되지 않고 프로세스 일부를 메모리에 계속 유지해서 자식 프로세스가 종료될 때 부모 프로세스가 상태를 검사할 수 있도록 한다.
부모 프로세스가 종료된 자식 프로세스를 기다렸다면 자식 프로세스는 완전히 종료된다.
부모 프로세스가 종료된 자식 프로세스를 기다리지 않았다면, 좀비 프로세스가 된다.
init 프로세스는 자기에게 딸린 자식 모두를 기다려서 새로 입양된 프로세스가 영원히 좀비로 남지 않도록 한다.
Last updated