Process : 실행 중인 프로그램
윈도우 기준으로 Ctrl + Shift + Del, 리눅스는 터미널에 top 또는 htop 을 입력하면 현재 실행 중인 프로세스들을 볼 수 있습니다. 사실 윈도우 유저의 경우 이 목록으로 현재 컴퓨터에서 어떤 프로그램들이 실행 중인지 확인하고 응답하지 않는 프로그램을 죽일 때 많이 보았을 것입니다. 그게 바로 프로세스였던 것이죠. 컴퓨터를 사용한다면 프로세스는 새로운 개념이 아니라는 것입니다.
앞선 글 'What is OS?'에서 폰 노이만 구조는 '프로그램 내장 방식'을 최초로 도입했고, 현대의 컴퓨터들도 그 구조는 조금 다르지만 기반은 폰 노이만 구조를 갖고 있다고 얘기했었습니다. 즉, 실행시킬 프로그램들을 메모리에 저장해서 쓴다는 말이죠. 그럼 저장된 프로그램은 당연히 용량을 갖을 것이고, 어떤 종류를 저장했냐에 따라서도 하나의 프로그램이 갖는 용량을 세분화할 수 있을 것입니다. 이를 나타낸 것이 프로세스의 메모리 구조입니다.

위의 그림은 하나의 프로세스가 가지는 메모리 구조입니다. 요소 하나하나에 대해 알아보겠습니다.
프로그램의 코드 자체를 저장합니다.
프로그램 내의 전역변수와 정적변수를 저장합니다.
📝 BSS (Block Started by Symbol)
data 영역에서 좀 더 세부적으로 들어가면 BSS 영역이 있습니다. 여기에는 uninitialized data, 즉 선언은 되었지만 특정 값으로 초기화되지 않은 전역 및 지역 변수가 할당됩니다.
stack 영역은 프로그램 실행시 순차적으로 실행되는 함수들을 stack 구조를 활용해 저장합니다. 만약 함수가 저장될 때, 호출되는 함수 내부에 지역변수가 있다면 그것 또한 stack영역에 저장이 됩니다.
호출되었던 함수가 종료되면 stack영역에 저장되었던 메모리도 pop 되어서 사라집니다.
stack 영역과 관련한 주요 특징들은 다음과 같습니다.
StackOverFlow Error 가 납니다. 유명한 개발자 커뮤니티인 스택오버플로의 대표이미지를 보면 이 스택오버플로 현상이 표현되어 있죠.
📝 스택 프레임 구조
프로세스 메모리구조를 세분화 한 것처럼 stack영역의 메모리 또한 세분화해서 그 구조를 살펴볼 수 있습니다. 그 것을 스택 프레임 구조라고 부릅니다. 그 안에서 변수가 어떻게 저장되는지, 함수가 끝나고 돌아갈 함수를 어떻게 찾는지 등을 살펴볼 수 있습니다. 이에 대해서는 다른 포스팅으로 정리해보도록 하겠습니다. 😄
heap 영역에는 프로그램 실행 중 동적으로 할당해서 쓸 수 있는 영역입니다. C언어의 경우에는 malloc() 이 대표적인 동적할당 함수이죠. JAVA의 new 키워드를 써서 만드는 객체 또한 동적할당에 해당이 됩니다. 이렇게 만들어진 변수들은 heap 영역에 할당이 됩니다. 이때 할당된 변수들은 stack과는 반대로 낮은 메모리 주소부터 가지게 됩니다.
영어로 heap이란 단어는 '더미' 라는 뜻 입니다. 왜 이런 이름이 붙었는지에 대해서 쉽게 설명하자면 특정한 구조없이 막 저장하기 때문입니다. 더미처럼 아무렇게나 쌓는다는 뜻이죠.
앞서 살펴보았던 stack의 경우 실제로 stack 구조를 활용해서 함수들을 관리하기 때문에 함수들이 종료되어서 stack에서 빠져나간다고 해도 중간중간에 빈 메모리 영역들이 남지 않습니다. 하지만 heap의 경우는 그렇지 않습니다. 할당되었던 변수가 해제가 될 경우 그 자리가 빈 공간이 됩니다. 따라서 새로운 변수가 heap 영역에 할당되려고 할 때 빈 공간을 찾는 시간이 발생하게 되죠. 이와 같은 이유 때문에 메모리와 관련한 속도는 heap 영역이 stack 영역보다 느립니다.
이 글에 맨위에서 단축키를 눌러 실행되고 있는 프로세스들을 봤었죠? 아마 거기에 딱 한개의 프로세스만 있는 컴퓨터는 없을꺼에요. 컴퓨터는 동시에 여러 프로세스들을 같이 실행하고 있습니다. 마치 문서작업을 하면서 유튜브를 틀어놓고, 음악도 틀어놓을 수 있는 것처럼요.
그렇다면 이 프로세스들은 정말로 한 순간에 같이 일어나는 것일까요? 그건 아닙니다. 컴퓨터는 연산속도가 굉장히 빠르게 때문에 여러작업들을 한순간에는 하나씩 처리하되 빠르게 바꿔가면서 많은 프로세스들을 처리하는 것이죠.
따라서 여러 프로세스들이 메모리에 올라가 있더라도 정확히 한 시점에서 실행되는 프로세스는 1개입니다. 그러면 나머지 프로세스들은 실행되는게 아니라면 어떤 상태에 있는 것일까요?

메모리에 올라온 프로세스의 상태는 위의 그림과 같이 총 5가지로 표현할 수 있습니다. 각 상태가 무엇인지 하나씩 살펴보겠습니다.
프로세스가 새로 생성되었을 때 New 상태에 속합니다. 이 단계에서는 만들어질 프로세스에 대한 메모리 할당, PCB 생성 등 새로운 프로세스가 만들어지기 위해 필요한 작업들이 수행됩니다.
프로세스가 실행될 준비가 되었다는 의미의 Ready 상태입니다. Ready 상태를 가질 수 있는 프로세스는 여러개가 될 수 있기 때문에 Queue를 사용하여 ready 상태의 프로세스들을 저장합니다. FIFO (First In First Out) 특징을 가지고 있는 큐를 이용했기 때문에 큐에 들어온 순서대로 실행이 될 것을 알 수 있습니다.
Ready 상태의 프로세스가 실행되면 Running 상태로 바뀌게 됩니다. 이 때 Ready 상태의 프로세스 중 어떤 프로세스를 실행시킬지 결정하는 녀석이 'Scheduler'이고, 스케쥴러가 Ready 상태의 프로세스 하나를 Running 상태로 바꾸는 것을 dispatch 라고 합니다. 프로세스 스케쥴러는 여러가지 방식이 있을 수 있고 그에 따라 서로 다른 프로세스가 Running 상태로 바뀔 수 있죠.
위와 같은 경우에서 실행 중인 프로세스는 아직 끝나지 않더라도 Ready 상태로 돌아갈 수 있습니다. 이 역시 어떤 프로세스 스케줄러를 쓰느냐에 따라 Ready 돌아가게 되는 조건이 다릅니다.
실행중인 프로세스는 계속해서 실행되기 위해서 특정 조건을 만족해야 하는 경우가 있습니다. 예를 들면 특정 파일들을 Load 해야될 수도 있고, 사용자로부터 입력을 받아야 될 수도 있죠. 이런 경우 그 조건이 만족되기 전까지는 더 이상 프로세스가 실행될 수 없고 상태가 Waiting 으로 바뀌게 됩니다. 그리고 알맞은 Waiting Queue로 가서 기다리게 되죠. 그리고 조건을 만족하게 되면 다시 ready queue로 돌아가서 실행되기 위한 줄을 서게 됩니다.
프로세스의 실행이 모두 끝나고 마치는 상태입니다. 이 상태에서는 프로세스의 실행에 할당했던 자원들을 회수하는 작업이 이루어집니다.
📝 Process Queues
상태에 관한 이야기를 하며 ready queue, waiting queue를 볼 수 있었습니다. 이 큐들은 요소로 PCB (Process Control Block) 을 가지는 linked-list로 구현이 되어있습니다. PCB는 쉽게 말해서 진행중인 프로세스의 상태를 저장하는 하나의 클래스와 같은 자료구조입니다. 따라서 큐에서 요소를 꺼낸다는 말은 프로세스의 진행 상태를 불러온다는 뜻이 되는 것이죠.
이번 글을 쓰며 든 생각은... 정리할 게 엄청 늘었다 라는 생각입니다.😵 위의 글에서 언급했던 스택 프레임 구조, PCB, 프로세스 스케쥴러 등... 물론 이미 너무 정리를 잘 해주신 분들이 많지만 글로 쓰는 것만큼 제걸로 만드는 확실한 방법이 없기에 이후 포스팅을 해야겠다는 생각이 들었습니다.
오타나 잘못된 부분에 대한 지적은 언제나 환영이며 질문이 있으시다면 댓글로 남겨주시면 감사드리겠습니다. 😄