3-1공부/운영체제

4. 프로세스

KGW2027 2022. 4. 18. 22:11
728x90
반응형

프로세스

 - 주 기억 장치의 프로그램이 CPU에 의해 처리 및 실행되는 상태, 메모리에 올라온 동적 상태를 의미한다.

 - PCB(Process control block)의 존재로 명시되며, Dispatch가 가능한 단위이다.

 

 

다중 프로그래밍

 - 여러 프로그램을 동시에 실행하는 것으로, 프로그램들은 메모리 내에서 상호 독립적인 위치에 존재한다.

 - 이 때, 하나의 프로그램이 여러 프로세스가 될 수 있다. ( 다중 인스턴스 )

 

 

로딩 ( Loading )

 - 실행 파일을 메모리에 적재(Load)하는 과정.

 - 프로그램을 위한 메모리 공간을 할당한다. ( Memory Allocation )

->외부 라이브러리 (dll 등..)을 참조한다. ( Linking )

->상대 주소를 절대 주소로 변환한다. ( Relocation )

->실제 프로그램과 데이터를 메모리에 적재한다. ( Loading )

 

 

프로세스의 생명 주기

 1. 생성 상태 : 프로세스가 생성된 후 PCB를 발급받음.

 

 2. 준비 상태 : PCB를 받은 프로세스가 자기 차례를 기다림. ( 준비 Queue에서 대기 )

 

 3. 실행 상태 : 프로세스를 준비 Queue에서 가져와 작업 실행 ( Dispatch )

 

 4. 완료 상태 : 프로세스가 종료되어 PCB가 제거됨.

 - 할당된 CPU 사용시간 초과(Timeout)시, 스스로 CPU 사용을 양보한다. (Interrupt)

 - 입출력 요청 : 자원 대기 상태로 전환, 대기 큐에 삽입 후 자원 할당이 완료되면 준비 큐에 입력한다.

 

 5. 대기 상태 : 프로세스가 자원 요청 후, 대기 큐에서 자원 할당 완료를 대기한다.

 - 대기 Queue는 List형태로 큐를 구성하며, 이는 큐가 아니라 Array, heap, tree 등도 가능하다.

 

 6. 보류 상태 : 프로세스가 모종의 이유로 인해 실행이 미뤄져 메모리에서 쫓겨난 상태.

  - Memory full, Program Error, Malware, Long period, I/O delay 등의 이유가 있다.

 

준비 상태와 실행 상태가 전환되는 과정을 `Context Switching` 이라고 한다.

 

Context Switching ( 문맥 교환 )

 - 한 프로세스에서 다른 프로세스로 CPU를 넘겨주는 과정.

 - 실행 상태에서 대기/완료 상태로 나가는 프로세스의 PCB에는 지금까지의 작동 과정을 저장한다.

 - 실행 상태로 들어오는 프로세스의 PCB의 내용을 CPU에 세팅한다.

 

시분할 (Time-Slicing)

 - CPU에서 프로세스들이 번갈아가며 실행된다. (동시 실행 X)

 - 어떤 순서로 번갈아 가며 작업하는가? 어떻게 번갈아가게 하는가?

 

PCB ( Process Control Block ) 구조

 - PCB들은 PCB 테이블, 프로세스 테이블에서 관리된다.

 - PCB에는 프로세스 위치 포인터, 프로세스 상태, 식별자(PID), 다음 명령어 주소(PC), 레지스터 정보, 메모리 관리 정보 등이 포함되어 있다.

 윈도우에서의 PCB는 NtQuestInformationProcess에 데이터 저장되어 있다.

 

메모리 주소 : 메모리 주소는 메모리 내의 위치 식별자이다.

CPU 주소 (물리 메모리 주소) : CPU 버스의 크기에 의해 결정되며, CPU 주소 공간보다 큰 메모리는 액세스 불가능

프로세스 주소 : 프로세스가 실행중에 접근 할 수 있도록 허용된 최대 범위 ( 세그먼테이션, CPU View )

 - 모든 프로세스는 자신만의 가상 주소 공간을 가지며, 자신이 CPU 전체를 독점하는 것처럼 느낌

   ( Logical Memory, Process View)

 - 사용자 공간 ( Code, Data, Heap, Stack 등...), 커널 공간( OS 저장 )이 나눠진다.

 Q. 프로세스에서는 왜 가상메모리를 사양하는 것일까?

  - 메모리 확장성 : 물리적 메모리는 한정적이지만, 가상 메모리는 더 큰 공간으로 구성 가능하다.

   -> 초과된 공간은 저장 장치의 구분 없이 보조 기억장치 등을 활용해 하나의 가상 공간으로 이용한다.

  - 메모리 격리 : 각 프로세스는 다른 프로세스를 신경 쓸 필요 없이, 격리되어서 보호된다.

   -> 모든 프로그램에 동일한 메모리 공간을 제공하기 위해서이다.

  => RTOS 등은 가상메모리를 사용하지 않고 직접 접근하는 방식을 사용하기도 한다.

 

 

메모리의 프로세스 적재

 - 컴파일 시간에 결정되는 크기

  1. 코드 영역 : 실행될 프로그램 코드가 적재되는 영역

  2. 데이터 영역 : 전역 변수와 정적 데이터 공간으로, 프로세스 적재시 할당되고, 종료시 소멸된다.

 - 실행 시간에 결정되는 크기

  1. 힙 영역 : 프로세스가 실행 도중 동적으로 사용할 수 있도록 할당된 공간

  2. 스택 영역 : 함수가 실행될 때 사용될 데이터를 위해 할당된 공간.

 Q. 프로세스는 왜 데이터 영역을 나누는가?

  - 공유할 수 있는 데이터는 공유하여, 메모리 사용량을 줄이기 위해서이다. (커널공간은 링크하여 사용한다.)

  - 코드 영역은 컴파일 이후 Read-only 되므로, 여러 개 실행 시 영역 공유로 효율이 상승한다.

  - 데이터 영역은 프로그램이 구동되는동안 항상 접근하므로, 독립적인 영역이 필요하다.

  - 힙,스택 영역은 실행 중간중간 필요할 때 마다 할당받아야 하므로, 필요량이 예측 불가능하다.

   -> 동적 공간을 위부터 사용(힙), 아래부터 사용(스택)으로 나누어서 효율적으로 사용한다.

 

 

프로세스의 생성복사

 - 프로세스를 메모리에 올리는 것 만으로는 프로세스가 만들어지지 않는다. ( PCB가 필요 )

  -> 메모리에 올라와도, PCB가 없다면 OS가 제어할 수 없다.

 프로세스가 언제 생성되는가?

  - 부팅과정에서 프로세스 생성

  - 사용자의 로그인 후, 제어를 위한 프로세스 생성 ( bash, explorer )

  - 사용자의 명령, 배치작업 실행, 응용프로그램의 시스템 호출로 인한 생성

  프로세스 생성 과정

  - 생성하려는 실행파일의 경로를 OS에 전달한다.

  - OS는 메모리에 프로그램을 적재하고, PCB공간을 할당(Malloc)받고 필요한 정보(PID 등..)를 채운다.

  - PCB에 프로세스 상태를 Ready로 표시하고, 준비 큐에 장착한다.

 

 1. fork()에 의한 생성

 리눅스에서는 fork()명령어가 있고, 윈도우에는 fork()와 exec()가 합쳐진 CreateProcess()가 있다.

 - 복사에 의한 생성으로, 기존에 있는 프로세스가 다른 프로세스를 생성하는 것이다.

 - UNIX 계열의 OS는 시스템이 부팅할 때, 0번 프로세스(INIT)만 자체 생성하며, 나머지는 모두 복제된다.

 Syscall :: Fork()

 - 실행중인 프로세스와 똑같은 프로세스를 하나 더 만든다. ( int child_pid = fork(); }

 - 부모 프로세스와 모든 환경, 메모리 등이 똑같다. ( 동일한 카피, 독립된 주소 공간만 다름 )

 - PID는 당연히 부모와 다르며, PPID, CPID를 가진다.

 - 자식은 부모의 PC값 까지 복제하므로, fork() 실행 이전의 라인은 실행할 수 없다.

 장점 : 속도가 빠르고, 자원 상속에 유리하다. 시스템 관리가 효율적이다.

 단점 : 맨 처음 프로세스 외에 다른 동작을 수행할 수 없다. -> exec() 명령어

 

 Syscall :: Exec() || Process Overlay

 - 기존의 프로세스를 새로운 프로세스로 전환하여 재사용하는 함수이다.

 - 새로운 프로세스를 생성하는 것이 아니라, PID 변경없이 새로운 프로그램을 적재하는 것이다.

 - 메모리와 데이터 영역에는 새로운 코드와 변수, 힙스택 영역은 리셋된다.

 - PCB에서는 PID, PPID, CPID를 제외한 모든 정보가 리셋된다.

 

Syscall :: Wait()

 - 자식 프로세스의 종료 신호를 기다렸다가, 종료 신호를 수신하면 이어서 실행한다.

 - SIGCHLD 신호(자식 프로세스 종료)를 보내는 것이다.

 

Syscall :: Exit()

 - 작업 종료를 알리는 신호이다.

 - 부모 프로세스가 자식 프로세스의 Exit() 콜을 확인해야 자식 프로세스가 제대로 종료된다.

  -> 만약 확인하지 못하면 자식 프로세스는 좀비 프로세스가 된다. (PCB가 제거되지않음, 메모리 점유 X)

  -> 그러나, PCB의 낭비가 발생하고, 커널이 유지할 수 있는 PCB 테이블에는 한계가 있기 때문에, 많은 좀비프로세스는 시스템 성능에 영향을 준다.

 => 부모 프로세스를 강제 종료하여 좀비를 고아(Orphan)화 시켜, init프로세스의 자식으로 이동시킬 수 있다.

      이를 통해, init에서 wait()를 호출 해 좀비프로세스를 제거한다.

 

 종료 과정 : 프로세스 자원 반환 > PCB 상태 변경 > 자식 프로세스를 Init 프로세스로 이동 > 부모 프로세스에게 종료 신호 전송 > 자식프로세스 PCB제거.

 

프로세스는 일반적으로 부모-자식 관계이며, #0 #1 #2 등 앞의 프로세스는 OS차원에서 부팅시 생성된다.

 

UNIX OS에서의 프로세스 생명주기

 - fork()를 통해 복제 후, exec()를 통해 필요한 프로세스로 전환 후 실행한다.

 - 부모 프로세스는 wait()를 통해 자식의 종료를 대기하며, 자식은 exit()를 통해 종료를 부모에게 알린다.

 - 모든 프로세스의 최초의 조상은 1번 프로세스 INIT이다.

 - syscall abort()는 부모 프로세스가 자식 프로세스를 죽이는 시스템 콜이다.

 - fork, exec를 통해 프로세스 생성이 간소화, 관리가 쉬워지고, 프로세스 간 통신(IPC, Inter-Process Communication)가 좋다.

 

Windows OS에서의 프로세스 생명주기

- CreateProcess() 명령어를 통해 자식프로세스에게 구체적으로 어떤 프로그램을 실행할 것인지 요구한다.

 

프로세스의 종류

 - CPU 집중 프로세스 : 계산 중심의 CPU작업, 배열곱, AI연산 등이 있다.

 - I/O 집중 프로세스 : 입출력 작업, 네트워크 전송, 파일 I/O, 서버 등이 있다.

=> 운영체제에서는 입출력 집중 프로세스를 CPU 집중 프로세스보다 우선순위를 높게 둔다. ( IO > CPU )

 

프로세스의 문제점

 - 프로세스 생성의 오버헤드가 큼 ( 메모리 할당 > fork > PCB 생성... )

 - Process Context Switching의 오버헤드도 큼. ( 기존 처리하던 정보 저장, 처리 영역 저장.. )

 - 프로세스간 통신이 어려움 ( 프로세스들은 완전히 독립적인 주소 공간을 가짐 -> 개입하기 힘듬 )

 

ex) 미디어 플레이어를 보자. 영상 재생, 소리 재생, 자막 처리 등의 기능들이 동시에 이루어진다.

  -> 이 모든 작업이 Context switching으로 진행되기에는 너무 무거움.

  -> Thread를 사용한다.

 

728x90
반응형