강의
운영체제의 역할
1.
시스템 자원(System Resource) 관리자
•
Operating System 또는 OS라고 부릅니다.
•
시스템 자원 = 컴퓨터 하드웨어
◦
CPU (중앙처리장치) : 각 프로그램이 얼마나 CPU를 사용할지를 결정할 수 없습니다.
◦
Memory (DRAM, RAM) : 각 프로그램이 어느 주소에 저장되어야 하는지 어느 정도의 메모리 공간을 확보해줘야 하는지를 결정할 수는 없습니다.
◦
I/O Devices (입출력장치) : 스스로 표시할 수는 없습니다.
◦
SSD, HDD (저장매체) : 어떻게, 어디에 저장할지는 결정할 수 없습니다.
2.
사용자와 컴퓨터간의 커뮤니케이션 지원
3.
컴퓨터 하드웨어와 응용 프로그램 제어
대표적인 운영체제
•
Windows OS
•
Mac OS
•
UNIX
◦
UNIX 계열 OS (UNIX와 사용법이나 OS 구조가 유사)
◦
LINUX OS (프로그래머나 전공자라면 알아야 할 OS)
RTOS와 GPOS
•
RealTime OS (RTOS)
◦
응용 프로그램 실시간 성능 보장을 목표로 하는 OS
◦
정확하게 프로그램 시작, 완료 시간을 보장
◦
Hardware RTOS, Software RTOS
•
General Purpose OS (GPOS)
◦
프로세스 실행시간에 민감하지 않고 일반적인 목적으로 사용되는 OS
◦
Windows, Linux 등
응용 프로그램이란?
•
프로그램 = 소프트웨어
•
소프트웨어 = 운영체제, 응용 프로그램(엑셀, 파워포인트, 우리가 만든 프로그램 등)
•
응용 프로그램 = Application (PC) = App (Mobile)
운영체제와 응용 프로그램 간의 관계
•
운영체제는
◦
응용 프로그램을 관리
◦
응용 프로그램을 실행
◦
응용 프로그램 간의 권한을 관리
◦
응용 프로그램을 사용하는 사용자도 관리
◦
사용자가 사용하는 응용 프로그램이 효율적으로 적절하게 동작하도록 지원
◦
응용 프로그램이 요청하는 시스템 리소스를 효율적으로 분배하고 지원
운영체제의 역사
•
1950년대~
◦
운영체제가 없었다.
◦
프로그램이 시스템 자원을 직접 제어
•
1960년대~
◦
배치 처리 시스템
•
1970년대~
◦
시분할 시스템/멀티 태스킹 시스템
◦
UNIX OS (C언어)
•
1980년대~
◦
GUI 환경을 제공
◦
개인용 컴퓨터 시대 도래
•
1990년대~
◦
다양한 응용 프로그램이 활성화
◦
인터넷(네트워크 기술) 발달
◦
오픈 소스 운동 활성화
•
2000년대~
◦
오픈 소스가 더더욱 활성화
◦
가상 머신 발전
◦
대용량 병렬 처리 발전
운영체제, 응용 프로그램, 컴퓨터 하드웨어(시스템 리소스) 간의 관계
•
도서관으로 비유
◦
운영체제는 도서관
◦
응용 프로그램은 시민
◦
컴퓨터 하드웨어는 책
•
운영체제의 역할
◦
시민(응용 프로그램)은 도서관(운영체제)에 원하는 책(자원)을 요청
◦
도서관(운영체제)은 적절한 책(자원)을 찾아서 시민(응용 프로그램)에게 빌려줌
◦
시민(응용 프로그램)이 기한이 다 되면 도서관(운영체제)이 해당 책(자원)을 회수
•
실제로 비유
◦
운영체제는 응용 프로그램이 요청하는 메모리를 허가하고 분배한다
◦
운영체제는 응용 프로그램이 요청하는 CPU 시간을 제공한다
◦
운영체제는 응용 프로그램이 요청하는 IO Devices 사용을 허가/제어한다
운영체제는 사용자를 위해 인터페이스를 제공
•
쉘(Shell)
◦
사용자가 운영체제 기능과 서비스를 조작할 수 있도록 인터페이스를 제공하는 프로그램
◦
쉘은 터미널 환경(CLI)과 GUI 환경 두 종류로 분류
운영체제는 응용 프로그램을 위해서도 인터페이스를 제공
•
API (Application Programming Interface)
◦
각 언어별 함수로 제공 (= 요청서)
◦
보통은 라이브러리 형태로 제공
◦
파일을 오픈하기 위한 C언어의 open() 함수도 API의 일종
◦
쉘 (Shell) 또한 API를 사용해서 처리
•
시스템 콜
◦
시스템 콜 또는 시스템 호출 인터페이스
◦
운영체제가 운영체제 각 기능을 사용할 수 있도록 시스템 콜이라는 명령 또는 함수를 제공
◦
API 내부에는 시스템 콜을 호출하는 형태로 만들어지는 경우가 대부분
◦
시스템 콜 정의 예 → POSIX API, 윈도우 API
운영체제를 만든다면?
1.
운영체제를 개발 (kernel)
2.
시스템 콜을 개발
3.
API (Library) 개발
4.
Shell 프로그램 개발
5.
응용 프로그램 개발
CPU Protection Rings
•
CPU도 권한 모드라는 것을 가지고 있음
◦
사용자 모드 (user mode)
▪
응용 프로그램이 사용
◦
커널 모드 (kernel mode)
▪
OS가 사용
▪
특권 명령어 실행과 원하는 작업 수행을 위한 자원 접근을 가능케 하는 모드
•
사용자 모드와 커널 모드의 비유
◦
함부로 응용 프로그램은 전체 컴퓨터 시스템을 해치지 않아야함
◦
사용자 모드
▪
주민등록등본은 꼭 동사무소 또는 민원24에서 특별한 신청서를 써야만 발급 받을 수 있음.
◦
커널 모드
▪
동사무소 직원은 특별한 권한을 가지고 주민등록등본 출력 명령을 실행할 수 있음
커널(Kernel)과 쉘(Shell)
•
커널(Kernel)이란?
◦
OS가 CPU가 쓸 때 사용하는 것
•
쉘(Shell)이란?
◦
커널을 둘러싸고 있는 사용자에게 인터페이스를 제공하는 것
•
시스템 콜은 커널 모드로 실행
◦
커널 모드에서만 실행 가능한 기능들이 있음
◦
커널 모드로 실행하려면 반드시 시스템 콜을 사용해야함
◦
시스템 콜은 운영체제가 제공
배치 처리 시스템 → 시분할 시스템, 멀티 태스킹
•
기존 배치 처리 시스템
◦
어떤 프로그램은 실행이 너무 시간이 많이 걸려서 다른 프로그램이 실행하는데 시간을 많이 기다려야 한다
◦
동시에 여러 응용 프로그램을 실행시키고 싶어함 → 멀티 태스킹
◦
여러 사용자가 동시에 하나의 컴퓨터를 사용하고 싶어함 → 시분할 시스템
•
시분할 시스템
◦
다중 사용자 지원을 위해 컴퓨터 응답 시간을 최소화하는 시스템
•
멀티 태스킹
◦
단일 CPU에서 여러 응용 프로그램이 동시에 실행되는 것처럼 보이도록 하는 시스템
멀티 태스킹 vs 멀티 프로세싱 vs 멀티 프로그래밍
•
멀티 태스킹
◦
단일 CPU
•
멀티 프로세싱
◦
여러 CPU
•
멀티 프로그래밍과 Wait
◦
멀티 프로그래밍
▪
최대한 CPU를 많이 활용하도록 하는 시스템
▪
시간 대비 CPU 활용도를 높이자
▪
응용 프로그램을 짧은 시간 안에 실행 완료를 시킬 수 있음
◦
Wait
▪
응용 프로그램은 온전히 CPU를 쓰기 보다 다른 작업을 중간에 필요로 하는 경우가 많습니다.
•
응용 프로그램이 실행되다가 파일을 읽는다
•
응용 프로그램이 실행되다가 프린팅을 한다
▪
간단히 저장매체로부터 파일 읽기를 기다리는 시간으로 가정
프로세스란?
•
실행 중인 프로그램을 프로세스라고 함
◦
프로세스 : 메모리에 올려져서 실행 중인 프로그램
◦
코드 이미지(바이너리) : 실행 파일 ex. ELF format
•
프로세스 = 작업 = task = job
•
응용 프로그램 ≠ 프로세스
◦
응용 프로그램은 여러 개의 프로세스로 이루어질 수 있음
◦
하나의 응용 프로그램은 여러 개의 프로세스가 상호작용을 하면서 실행될 수 있음
프로세스의 상태
•
running state
◦
현재 CPU에서 실행 상태
•
ready state
◦
CPU에서 실행 가능 상태 (실행 대기 상태)
•
block state
◦
특정 이벤트 발생 대기 상태
프로세스의 상태간 관계
•
running → block → ready → running
•
running → ready → running
스케줄러
•
개념
◦
스케줄링 알고리즘에 의해 프로세스의 실행을 관리한다
•
선점형 스케줄러 (Preemptive Scheduling)
◦
하나의 프로세스가 다른 프로세스 대신에 CPU를 차지할 수 있음
▪
프로세스 running 중에 스케줄러가 이를 중단시키고 다른 프로세스로 교체 가능
◦
시분할 시스템을 위한 기본 알고리즘 사용
▪
ex) RoundRobin 스케줄링
•
비선점형 스케줄러 (Non-preemptive Scheduling)
◦
하나의 프로세스가 끝나지 않으면 다른 프로세스는 CPU를 사용할 수 없음
▪
프로세스가 자발적으로 block 상태로 들어가거나 실행이 끝났을 때만 다른 프로세스로 교체 가능
◦
어떤 프로세스를 먼저 실행시킬지에 대한 알고리즘 사용
▪
ex) FIFO(FCFS), SJF, Priority-based 스케줄링
스케줄링 알고리즘 종류
•
FIFO 스케줄링 = FCFS (First Come First Served) 스케줄링
◦
가장 간단한 스케줄 (배치 처리 시스템과 유사)
•
최단 작업 우선 스케줄링 = SJF(Shortest Job First) 스케줄링
◦
가장 프로세스 실행시간이 짧은 프로세스부터 먼저 실행을 시키는 알고리즘
•
우선순위 기반 스케줄링 = Priority-Based 스케줄링
◦
정적 우선순위
▪
프로세스마다 우선순위를 미리 지정
◦
동적 우선순위
▪
스케줄러가 상황에 따라 우선순위를 동적으로 변경
•
Round Robin 스케줄러
◦
시분할 시스템을 기반으로 정해진 실행 시간만큼 선점하여 반복해서 실행 시키는 알고리즘
인터럽트
•
인터럽트란?
◦
CPU가 프로그램을 실행하고 있을 때, 입출력 하드웨어 등의 장치나 또는 예외상황이 발생하여 처리가 필요할 경우에 운영체제가 CPU에 알려서 처리하는 기술
•
이벤트와 인터럽트
◦
인터럽트는 일종의 이벤트로 불리며 이벤트에 맞게 운영체제가 처리함
인터럽트 종류
•
내부 인터럽트 (소프트웨어 인터럽트)
◦
주로 프로그램 내부에서 잘못된 명령 또는 잘못된 데이터 사용 시 발생
▪
예외 상황 (0 으로 나누기)
▪
사용자 모드에서 허용되지 않은 명령 또는 공간 접근 시
▪
계산 결과가 Overflow/Underflow 날 때
•
외부 인터럽트 (하드웨어 인터럽트)
◦
주로 하드웨어(프로그램 외부)에서 발생되는 이벤트
▪
전원 이상
▪
기계 문제
▪
IO 관련 이벤트
▪
Timer 이벤트
인터럽트가 사용되는 곳
•
선점형 스케줄러 구현
◦
프로세스 running 중에 스케줄러가 이를 중단시키고 다른 프로세스로 교체하기 위해 현재 프로세스 실행을 중단시키려면 스케줄러 코드가 실행돼서 현 프로세스 실행을 중지시켜야함
◦
running → ready
•
타이머
◦
하드웨어로부터 일정 시간마다 타이머 인터럽트를 운영체제에 알려줌
◦
선점형 스케줄러 구현을 위해 사용
•
IO Device와의 커뮤니케이션
◦
저장매체에서 데이터 처리 완료시 프로세스를 깨워야함
◦
waiting → ready
•
예외 상황 핸들링
◦
CPU가 프로그램을 실행하고 있을 때 입출력 하드웨어 등의 장치나 또는 예외 상황이 발생한 경우 CPU가 해당 처리를 할 수 있도록 CPU에 알려줘야함
시스템 콜
mov eax, 1 #시스템 콜 번호
mov ebx, 0 #인자
int 0x80 #int는 CPU OP code로 인터럽트 명령이고 0x80은 시스템 콜 인터럽트 번호
Bash
복사
•
시스템 콜 실행을 위해서는 강제로 코드에 인터럽트 명령을 넣어 CPU에게 실행시켜야한다.
1.
시스템 콜 인터럽트 명령을 호출
2.
CPU가 사용자 모드에서 커널 모드로 변경
3.
IDT(Interrupt Descriptor Table)에서 0x80에 해당하는 주소(함수)를 찾아서 실행
4.
system_call() 함수에서 eax로부터 받은 시스템 콜 번호에 맞는 시스템 콜 함수로 이동
5.
해당 시스템 콜 함수를 실행 후 다시 커널 모드에서 사용자 모드로 변경하고 프로세스 진행
•
사용자/커널 모드, 프로세스, 인터럽트의 관계
1.
프로세스 실행 중 인터럽트 발생
2.
현 프로세스 실행 중단
3.
인터럽트 처리 함수 실행 (운영체제)
4.
현 프로세스 재실행
•
인터럽트와 IDT(Interrupt Descriptor Tabel)
◦
인터럽트는 미리 정의되어 각각 이벤트 번호와 실행 함수를 가리키는 주소가 기록되어 있음
▪
어디에? IDT(Interrupt Descriptor Table)에 이벤트 번호와 함수의 주소를 매핑하여 기록
▪
언제? 컴퓨터 부팅 시 운영체제가 기록
▪
어떤 코드? 운영체제 내부 코드
◦
리눅스의 예
▪
0~31 : 소프트웨어 인터럽트 (예외상황들로 일부는 정의 안된 채로 남겨져 있음)
▪
32~47 : 하드웨어 인터럽트 (주변 장치의 종류/갯수에 따라 변경 가능)
▪
128 : 시스템 콜
프로세스의 구조
•
프로세스 구조
◦
code : 코드
◦
data : 컴파일 단계에서 생성되는 데이터
▪
BSS : 초기화되지 않은 전역 변수
▪
DATA : 초기화된 전역 변수
◦
stack : 런타임 단계에서 생성되는 임시 데이터 (함수, 로컬 변수 등)
◦
heap : 런타임 단계에서 코드에 의해 동적으로 만들어지는 데이터
•
레지스터 구조
◦
PC(Program Counter) : 프로세스에서 실행 중인 code의 위치를 기록
◦
SP(Stack Pointer) : 프로세스에서 실행 중인 stack의 위치를 기록
◦
EAX : 함수의 리턴 값을 기록
◦
EBP : 함수 최상단의 Stack Pointer를 기록
컨텍스트 스위칭
•
PCB (Process Context Block)
◦
프로세스가 실행 중인 상태 정보를 캡쳐/구조화해서 저장하는 곳
•
스케줄러에 의해 컨텍스트 스위칭이 일어날 때
◦
Dispatch : PCB 정보를 CPU의 레지스터에 넣고 프로세스의 상태를 변경하는 것
프로세스간 커뮤니케이션
•
프로세스간 커뮤니케이션이 필요한 이유
◦
여러 프로세스 동시 실행을 통한 성능 개선
◦
복잡한 프로그램을 위한 프로세스간 통신 필요
•
프로세스의 공간
◦
하나의 프로세스는 최소 4GB의 주소 공간을 가짐
◦
0~3GB 까지는 사용자 모드, 나머지는 커널 모드
◦
모든 프로세스가 커널 공간은 공유
IPC (Inter Process Communication) 기법
•
File
◦
저장매체를 사용하기 때문에 속도가 느려 실시간성이 떨어짐
◦
다른 IPC 기법과는 달리 커널 공간을 사용하지 않음
•
Pipe
◦
pipe() 함수의 인자 중 fd[2]는 정수 배열로 fd[0]과 fd[1]의 할당되는 주소값이 각각 다름
◦
fork() 함수의 리턴 값 : 부모 프로세스는 프로세스ID, 자식 프로세스는 0
◦
write() 와 read() 함수를 통해 부모 → 자식의 단방향 통신
•
Message Queue
◦
msgget() 함수를 통해 특정 key 값을 갖는 메세지 큐의 ID를 반환 받음
◦
msgsnd() 함수를 통해 큐ID와 메세지가 담긴 변수를 전달하면 메세지를 송신
◦
msgrcv() 함수를 통해 큐ID와 메세지를 받을 변수를 전달하면 메세지를 수신
◦
부모/자식 관계가 필요 없이 어느 프로세스간에도 양방향 통신이 가능
•
Shared Memory
◦
커널 공간에 메모리 공간을 만들고 해당 공간을 변수처럼 사용하는 방식
◦
공유 메모리의 key를 가지고 여러 프로세스가 접근하여 쓰기/읽기 가능
◦
shmget() 함수를 통해 key와 사이즈를 전달하면 공유 메모리의 ID를 반환 받음
◦
shmat() 함수를 통해 공유 메모리 ID를 전달하면 공유 메모리의 주소를 반환 받음
◦
strcpy(), printf() 함수를 통해 공유 메모리 주소에 쓰기/읽기 가능
•
Signal
◦
유닉스에서 30년 이상 사용된 전통적인 기법으로 커널 또는 프로세스에서 다른 프로세스에 어떤 이벤트가 발생되었는지를 알려주는 기법
◦
커널 모드에서 사용자 모드로 전환 시 시그널을 처리
◦
프로세스 관련 코드에 관련 시그널 핸들러를 등록해서 해당 시그널 처리 실행
◦
주요 시그널
▪
kill -l 을 통해 확인 가능
▪
kill -i PID 를 통해 시그널을 보낼 수 있음
•
Socket
◦
기본적으로는 클라이언트와 서버 등 두 개의 다른 컴퓨터 간의 네트워크 기반 통신을 위한 기술
◦
하나의 컴퓨터 안에서 두 개의 프로세스 간의 통신 기법으로도 사용 가능
◦
로컬 환경 안에서 Network Layer를 쭉 타서 돌아올 땐 다른 프로세스로 돌아오는 방식
스레드
•
스레드란?
◦
Light Weight Process 라고도 함
◦
하나의 프로세스에 여러 개의 스레드 생성 가능
◦
스레드들은 동시에 실행 가능
•
프로세스 내에서 스레드 간 공간 공유
◦
프로세스 안에 있으므로 여러 스레드들이 프로세스의 데이터를 모두 접근 가능
◦
Stack 영역을 각 스레드별로 분리하고 Heap, Data, Code 영역은 공유
•
스레드의 장점
1.
사용자에 대한 응답성 향상
•
스레드를 동시에 실행하여 원활한 대응이 가능
2.
자원 공유 효율
•
IPC 기법과 같이 프로세스간 자원 공유를 위해 번거로운 작업이 필요 없음
•
프로세스 안에 있으므로 프로세스의 데이터를 모두 접근 가능
3.
작업이 분리되어 코드가 간결
•
작성하기 나름
•
스레드의 단점
1.
프로세스 영향
•
멀티 프로세스와는 다르게 스레드 중 한 스레드만 문제가 있어도 전체 프로세스가 영향을 받음
2.
컨텍스트 스위칭을 통한 성능 저하
•
Linux는 스레드를 프로세스와 같이 다루기 때문에 모든 스레드를 스케줄링하므로 컨텍스트 스위칭이 빈번하게 일어남
•
프로세스 vs 스레드
◦
프로세스는 독립적, 스레드는 프로세스의 서브셋
◦
프로세스는 각각 독립적인 자원을 가짐, 스레드는 프로세스의 자원을 공유
◦
프로세스는 자기만의 주소 영역을 가짐, 스레드는 주소 영역을 공유
◦
프로세스 간에는 IPC 기법으로 통신해야함, 스레드는 필요 없음
스레드의 동기화 이슈
•
스레드 동기화 이슈 코드
◦
동일 자원을 여러 스레드가 동시 수정 시 각 스레드 결과에 영향을 준다.
•
스레드 상호 배제 코드
◦
여러 스레드가 변경하는 공유 변수에 대해 Exclusive Access 필요
◦
어느 한 스레드가 공유 변수를 갱신하는 동안 다른 스레드가 동시 접근하지 못하도록 막아라
임계 자원과 임계 영역 그리고 Locking 메커니즘
•
임계 자원 (Critical Resource)
◦
여러 스레드가 동시에 접근하면 안되는 자원
◦
위 예제에선 g_count 전역 변수
•
임계 영역 (Ciritical Section)
◦
여러 스레드가 동시에 실행하면 안되는 코드 영역
◦
위 예제에선 lock.acquire()와 lock.release() 사이에 for문
•
임계 영역에 대한 접근을 막기 위해 Locking 메커니즘이 필요
◦
Mutex (binary semaphore)
▪
임계 영역에 하나의 스레드만 들어갈 수 있음
◦
Semaphore
▪
임계 영역에 여러 스레드가 들어갈 수 있음
▪
counter를 두어서 동시에 리소스에 접근할 수 있는 허용 가능한 스레드 수를 제어
Semaphore
•
기본 동작
◦
P : 검사 (임계 영역에 들어갈 때)
▪
S 값이 1 이상이면 임계 영역 진입 후 S 값 1 차감
▪
S 값이 0이면 대기
◦
V : 증가 (임계 영역에서 나올 때)
▪
S 값을 1 더하고 임계 영역을 나옴
◦
S : 세마포어 값 (초기 값만큼 여러 프로세스가 동시 임계 영역 접근 가능)
•
바쁜 대기 (busy waiting)
◦
S가 0인 경우 임계 영역에 들어가기 위한 반복문을 수행하는 과정
◦
loop를 계속 돌기 때문에 CPU를 계속 실행시켜 성능을 저하
•
대기 큐
◦
바쁜 대기를 해결하기 위한 운영체제의 방법
◦
S가 0인 경우 바쁜 대기 대신 대기 큐에 넣은 후 슬립
◦
S가 1보다 큰 경우 대기 큐에서 프로세스를 꺼내 재실행
•
POSIX Semaphore
◦
sem_open() : 세마포어를 생성
◦
sem_wait() : 임계 영역 접근 전 세마포어를 잠그고 세마포어가 잠겨있다면 풀릴 때까지 대기
◦
sem_post() : 공유 자원에 대한 접근이 끝났을 때 세마포어 잠금을 해제
교착 상태 (Deadlock)
•
교착 상태란?
◦
두 개 이상의 작업이 서로 상대방의 작업이 끝나기만을 기다리고 있기 때문에 다음 단계로 진행하지 못하는 상태
◦
배치 처리 시스템에서는 일어나지 않고 멀티 프로세스 혹은 멀티 스레드에서 일어날 수 있음
•
발생 조건
◦
다음 네 가지 조건이 모두 성립될 때 교착 상태 발생 가능성이 있음
1.
상호배제 (Mutual Exclusion) : 프로세스들이 필요로 하는 자원에 대해 배타적인 통제권을 요구한다.
2.
점유대기 (Hold and Wait) : 프로세스가 할당된 자원을 가진 상태에서 다른 자원을 기다린다.
3.
비선점 (Non-Preemption) : 프로세스가 어떤 자원의 사용을 끝낼 때까지 그 자원을 뺏을 수 없다.
4.
순환대기 (Circular Wait) : 각 프로세스는 순환적으로 다음 프로세스가 요구하는 자원을 가지고 있다.
•
해결 방법
◦
교착 상태 예방
▪
4가지 조건 중 하나를 제거하는 방법
1.
상호배제 조건의 제거 : 임계 영역 제거
2.
점유대기 조건의 제거 : 한 번에 모든 필요 자원 점유 및 해제
3.
비선점 조건의 제거 : 선점 가능 기법을 만들어줌
4.
순환대기 조건의 제거 : 자원 유형에 따라 순서를 매김
◦
교착 상태 회피
▪
교착 상태 조건 중 1, 2, 3 제거 시 프로세스 실행 비효율성이 증대하므로 4만 제거
▪
순환대기 조건의 제거 : 자원 할당 순서를 정의하지 않음
◦
교착 상태 발견
▪
교착 상태가 발생했는지 점검하여 교착 상태에 있는 프로세스와 자원을 발견
◦
교착 상태 회복
▪
교착 상태를 일으킨 프로세스를 종료하거나 할당된 자원을 선점하여 프로세스나 자원을 회복
기아 상태 (Starvation)
•
기아 상태란?
◦
특정 프로세스의 우선 순위가 낮아서 원하는 자원을 계속 할당 받지 못하는 상태
•
교착 상태 vs 기아 상태
◦
교착 상태는 여러 프로세스가 동일 자원 점유를 요청할 때 발생
◦
기아 상태는 여러 프로세스가 부족한 자원을 점유하기 위해 경쟁할 때 특정 프로세스는 영원히 자원 할당이 안되는 경우를 주로 의미
•
해결 방법
◦
우선 순위 변경
▪
프로세스 우선 순위를 수시로 변경해서 각 프로세스가 높은 우선 순위를 가질 기회를 주기
▪
오래 기다린 프로세스의 우선 순위를 높여주기
▪
우선 순위가 아닌 요청 순서대로 처리하는 FIFO 기반 요청 큐 사용
가상 메모리 (Virtual Memory System)
•
가상 메모리의 필요성
◦
여러 프로세스 동시 실행 시 프로세스 메모리 영역 간에 침범 이슈
▪
프로세스 간 공간 분리로 프로세스 이슈가 전체 시스템에 영향을 주지 않음
◦
여러 프로세스 동시 실행 시 각 프로세스마다 메모리를 할당하기에는 메모리 크기의 한계
▪
리눅스는 하나의 프로세스가 4GB
▪
통상 메모리는 8GB, 16GB, 32GB
▪
폰노이만 구조 기반이므로 코드는 메모리에 반드시 있어야함
•
가상 메모리의 기본 아이디어
◦
프로세스는 가상 주소를 사용하고 실제 해당 주소에서 데이터를 읽고 쓸 때만 물리 주소로 바꿔줌
◦
가상 주소 (virtual address)
▪
프로세스가 참조하는 주소로 0~4GB의 주소
◦
물리 주소 (physical address)
▪
실제 메모리 주소로 RAM의 주소
MMU (Memory Management Unit)
•
가상 메모리 주소에 접근이 필요할 때 해당 주소를 물리 주소값으로 변환해주는 하드웨어 장치
◦
하드웨어 장치를 이용해야 주소 변환이 빠르기 때문에 별도 장치를 둠
•
CPU는 가상 메모리를 다루고 실제 해당 주소 접근 시 MMU 하드웨어 장치를 통해 물리 메모리 접근
페이징 시스템 (Paging System)
•
Paging
◦
크기가 동일한 Page로 가상 주소 공간과 이에 매칭하는 물리 주소 공간을 관리
◦
Page 번호를 기반으로 가상 주소/물리 주소 매핑 정보를 기록/사용
◦
하드웨어 지원이 필요
▪
Intel x86 (32bit) : 4KB, 2MB, 1GB
▪
Linux : 4KB
•
Page Table
◦
프로세스(4GB)의 PCB에 Page Table 구조체를 가리키는 주소가 들어 있음
◦
Page Table에는 가상 주소와 물리 주소간 매핑 정보가 있음
◦
PCB 등에서 해당 Page Table 접근 가능하고 관련 정보는 물리 메모리에 적재
•
구조
◦
page 또는 page frame
▪
고정된 크기의 block (Linux는 4KB)
◦
virtual address
▪
p : 가상 메모리 페이지
▪
d : p 안에서 참조하는 위치
▪
page가 4KB인 경우 가상 주소는 32bit이고 0~11bit는 변위(d), 12bit부터 나머지는 페이지 번호
▪
p + d → 실제 물리 메로리의 해당 데이터 위치
◦
valid-invalid bit
▪
Page Table에 등록된 page가 실제로 물리 주소에 존재하는지 확인하는 값
•
동작
◦
프로세스 생성 시 Page Table 정보를 생성하는 동작
1.
프로세스 구동 시 해당 Page Table의 base 주소가 별도 레지스터(CR3)에 저장
2.
CPU가 가상 주소 접근 시 MMU가 Page Table의 base 주소를 접근해서 물리 주소를 가져옴
◦
CPU가 프로세스의 특정 가상 주소 엑세스를 하기 위한 동작
1.
MMU가 해당 프로세스의 Page Table에 해당 가상 주소가 포함된 Page 번호가 있는지 확인
2.
Page 번호가 있으면 이 Page가 매핑된 첫 물리 주소를 알아내고 (p’)
3.
p’ + d 가 실제 물리 주소가 됨
다중 단계 페이징 시스템
•
32bit 시스템에서 4KB 페이지를 위한 페이징 시스템
◦
하위 12bit는 오프셋
◦
상위 20bit가 페이징 번호이므로 2^20 (1048576) 개의 페이지 정보가 필요함
◦
굳이 상위 20bit를 모두 페이징 번호로 사용할 필요가 없음
•
페이징 정보를 단계를 나누어 생성
◦
필요 없는 페이지는 생성하지 않으면 공간 절약 가능
◦
상위 20bit 중 10bit는 Page Directory, 나머지 10bit는 Page Table을 나타냄
◦
CR3 레지스터는 Page Directory의 base 주소를 가짐
◦
Linux는 기본적으로 3단계, 최근엔 4단계
TLB (Translation Lookaside Buffer)
•
메인 메모리를 엑세스하는 시간이 오래 걸리므로 페이지 정보를 캐싱하기 위한 하드웨어
페이징 시스템과 공유 메모리
•
프로세스간 동일한 물리 주소를 가리킬 수 있음
◦
물리 메모리 공간 공유로 공간 절약
•
물리 주소 데이터 변경 시도 시 그 때 물리 주소를 복사하고 변경
◦
메모리 할당 시간 절약으로 프로세스 생성 시간 절약
요구 페이징 (Demand Paging)
•
요구 페이징이란?
◦
프로세스 모든 데이터를 메모리로 적재하지 않고 실행 중 필요한 시점에서만 메모리로 적재
◦
더 이상 필요하지 않은 Page는 다시 저장매체에 저장하는 페이지 교체 알고리즘 필요
•
Page Fault Interrupt
◦
valid-invalid bit의 값이 invalid면 인터럽트를 발생시키고 운영체제는 해당 Page를 메모리에 적재
•
고찰
◦
페이지 폴트가 자주 일어나면?
▪
실행 되기 전에 해당 페이지를 물리 메모리에 올려야함 → 시간이 오래 걸림
◦
페이지 폴트가 안 일어나게 하려면?
▪
향후 실행/참조될 코드/데이터를 미리 물리 메모리에 올려야함 → 앞으로 있을 일을 예측 (신의 영역)
페이지 교체 알고리즘 (Page Replacement Policy)
•
운영체제가 특정 페이지를 물리 메모리에 올려야 하는데 물리 메모리가 다 차있는 경우
◦
기존 페이지 중 하나를 물리 메모리에서 저장 매체로 내리고 (저장)
◦
새로운 페이지를 해당 물리 메모리 공간에 올린다. (교체)
•
FIFO(First-In, First-Out) 알고리즘
◦
가장 먼저 들어온 페이지를 내리기
•
OPT(Optimal) 알고리즘
◦
최적 페이지 교체 알고리즘으로 앞으로 가장 오랫동안 사용하지 않을 페이지를 내리기
◦
일반 OS에서는 구현 불가
•
LRU(Least Recently Used) 알고리즘
◦
가장 오래 전에 사용된 페이지를 교체
◦
OPT 교체 알고리즘이 구현이 불가하므로 과거 기록을 기반으로 시도
•
LFU(Least Frequently Used) 알고리즘
◦
가장 적게 사용된 페이지를 교체
•
NUR(Not Used Recently) 알고리즘
◦
LRU와 마찬가지로 최근에 사용하지 않은 페이지부터 교체
◦
각 페이지마다 참조 비트(R), 수정 비트(M)를 둠
◦
(R,M)이 (0,0), (0,1), (1,0), (1,1)인 순서대로 페이지 교체
스레싱 (Thrashing)
•
반복적으로 Page Fault Interrupt가 발생해서 과도하게 페이지 교체 작업이 일어나 실제로는 아무 일도 하지 못하는 상황
•
메모리를 늘림으로써 스레싱 현상을 완화할 수 있음
세그멘테이션 (Segmentation)
•
세그멘테이션 기법
◦
가상 메모리를 서로 크기가 다른 논리적 단위인 세그먼트(Segment)로 분할
◦
크기가 다른 세그먼트 단위로 물리 메모리에 로딩
◦
ex) x86 리얼모드
x86 리얼모드란?
▪
CS(Code Segment), DS(Data Segment), SS(Stack Segment), ES(Extra Segment)로 세그먼트를 나누어 메모리 접근
•
세그먼트 가상주소
◦
v = (s, d)
▪
s : 세그먼트 번호
▪
d : 블록 내 세그먼트의 변위(오프셋)
페이징 기법 vs 세그멘테이션 기법
•
내부 단편화 (페이징 기법)
◦
페이지 블록만큼 데이터가 딱 맞게 채워져있지 않을 경우 공간 낭비
•
외부 단편화 (세그멘테이션 기법)
◦
물리 메모리가 원하는 연속된 크기의 메모리를 제공해주지 못하는 경우
•
페이징/세그멘테이션 기법 모두 하드웨어 지원 필요
◦
다양한 컴퓨터 시스템에 이식성을 중요시하는 리눅스는 페이징 기법을 기반으로 구현
파일 시스템
•
파일 시스템이란?
◦
운영체제가 저장매체에 파일을 쓰기 위한 자료구조 또는 알고리즘
•
파일 시스템이 만들어진 이유
1.
0과 1의 데이터를 비트로 관리하여 주소를 각각 부여하기엔 오버헤드가 너무 큼
2.
블록 단위로 관리하여 부여할 주소를 줄임 (보통 4KB)
3.
블록마다 고유 번호를 부여해서 관리
4.
사용자가 각 블록 고유 번호를 관리하기 어려우므로 추상적(논리적) 객체가 필요
5.
사용자는 파일 단위로 관리하며 각 파일에는 블록 단위로 관리
•
저장 매체에 효율적으로 파일을 저장하는 방법
1.
가능한 연속적인 공간에 파일을 저장하는 것이 좋음
2.
외부 단편화, 파일 사이즈 변경 문제로 불연속 공간에 파일 저장 기능 지원 필요
•
블럭 체인 : 블럭을 Linked List로 연결 (끝 블럭 찾기 어려움)
•
인덱스 블럭 기법 : 각 블럭에 대한 위치 정보를 기록 (끝 블럭 찾기 쉬움)
•
다양한 파일 시스템
◦
Windows
▪
FAT, FAT32, NTFS
▪
블럭 위치를 FAT라는 자료 구조에 기록
◦
Linux(Unix)
▪
ext2, ext3, ext4
▪
일종의 인덱스 블럭 기법인 inode 방식 사용
•
파일 시스템과 시스템 콜
◦
동일한 시스템 콜을 사용해서 다양한 파일 시스템을 지원 가능하도록 구현
◦
read/write 시스템 콜 호출 시 각 기기 및 파일 시스템에 따라 실질적인 처리를 담당하는 함수를 구현
◦
파일을 실제로 어떻게 저장할지는 다를 수 있음
inode 방식 파일 시스템
•
기본 구조
◦
수퍼 블럭
▪
파일 시스템 정보 및 파티션 정보 포함
◦
아이노드 블럭
▪
파일 상세 정보
◦
디스크(데이터) 블럭
▪
실제 데이터로 4KB의 공간을 가짐
•
파일
◦
inode 고유 값과 자료 구조에 의해 주요 정보 관리
◦
‘파일이름:inode’ 로 파일 이름은 inode 번호와 매칭
◦
파일 시스템에서는 inode를 기반으로 파일 엑세스
◦
inode 기반 메타 데이터 저장
•
inode 구조
◦
inode 기반 메타 데이터
▪
파일 권한, 소유자 정보, 파일 사이즈, 생성 시간 등 시간 관련 정보, 데이터 저장 위치
◦
Direct Blocks
▪
일반적으로 12개의 주소 공간이 실제 데이터 블럭의 주소를 가리킴
◦
Single Indirect (Indirect Blocks)
▪
실제 데이터 블럭의 주소(4byte)로 하나의 데이터 블럭(4KB)을 나눈 갯수 만큼의 주소를 가짐 (4MB)
◦
Double Indirect
▪
Single Indirect의 주소(4byte)로 하나의 Single Indirect 블럭(4KB)을 나눈 갯수 만큼의 주소를 가짐 (4GB)
◦
Triple Indirect
▪
Double Indirect의 주소(4byte)로 하나의 Double Indirect 블럭(4KB)을 나눈 갯수 만큼의 주소를 가짐 (4TB)
•
디렉토리 엔트리
◦
리눅스 파일 탐색 (/home/ubuntu/link.txt)
1.
각 디렉토리 엔트리(dentry)를 탐색
a.
각 엔트리는 해당 디렉토리 파일/디렉토리 정보를 갖고 있음
2.
‘/’ dentry에서 ‘home’을 찾고, ‘home’에서 ‘ubuntu’를 찾고, ‘ubuntu’에서 link.txt 파일 이름에 해당하는 inode를 얻음
가상 파일 시스템 (Virtual File System)
•
Network 등 다양한 기기도 동일한 파일 시스템 인터페이스를 통해 관리 가능
•
read/write 시스템 콜 사용, 각 기기별 read_spec/write_spec 코드 구현 (운영체제 내부)
리눅스의 철학과 특수 파일
•
모든 것은 파일이다
◦
모든 인터랙션은 파일을 읽고 쓰는 것처럼 이루어져 있음
◦
마우스, 키보드와 같은 모든 디바이스 관련된 기술로 파일과 같이 다루어짐
◦
모든 자원에 대한 추상화 인터페이스로 파일 인터페이스를 활용
•
디바이스
◦
블럭 디바이스 (Block Device)
▪
HDD, CD/DVD 와 같이 블럭 또는 섹터 등 정해진 단위로 데이터 전송
▪
I/O 송수신 속도가 높음
◦
캐릭터 디바이스 (Character Device)
▪
키보드, 마우스 등 byte 단위 데이터 전송
▪
I/O 송수신 속도가 낮음
Booting
•
부팅이란?
◦
컴퓨터를 켜서 동작시키는 절차
•
Boot 프로그램이란?
◦
운영체제 커널을 Storage에서 특정 주소의 물리 메모리로 복사하고 커널의 처음 실행 위치로 PC를 가져다 놓는 프로그램
•
부팅 과정
1.
CPU가 ROM의 BIOS의 주소를 읽음
2.
ROM은 실제 BIOS 프로그램을 로드하여 RAM(Memory)에 올림
3.
BIOS 프로그램이 하드웨어 초기화
4.
BIOS 프로그램이 저장매체 맨 앞에 있는 데이터인 MBR(Master Boot Record)을 읽어 Bootstrap Loader와 Partition Table을 RAM(Memory)로 읽어옴
5.
읽어 온 Partition Table에서 Boot Sector를 읽어 Boot Code를 RAM(Memory)로 읽어옴
6.
Boot Code를 통해 파티션 내의 커널 이미지의 위치를 찾은 후 RAM(Memory)로 읽어옴
7.
커널 이미지를 읽으며 운영체제 실행
가상 머신 (Virtual Machine)
•
가상 머신이란?
◦
하나의 하드웨어 (CPU, Memory 등)에 다수의 운영체제를 설치하고 개별 컴퓨터처럼 동작하도록 하는 프로그램
•
Virtual Machine Type1 VS Virtual Machine Type2
◦
Virtual Machine Type1 (native 또는 bare metal)
▪
운영 체제와 응용 프로그램을 물리적 하드웨어에서 분리하는 프로세스
▪
하이퍼 바이저 또는 버츄얼 머신 모니터 (VMM) 라고 하는 소프트웨어가 하드웨어에서 직접 구동
▪
ex) Xen, KVM
◦
Virtual Machine Type2
▪
하이퍼 바이저 또는 버츄얼 머신 모니터 (VMM) 라고 하는 소프트웨어가 Host OS 상위에 설치
▪
ex) VMWare, Parallels Desktop (Mac)
•
전가상화 VS 반가상화
◦
전가상화 (Full Virtualization)
▪
각 가상머신이 하이퍼 바이저를 통해서 하드웨어와 통신
▪
하이퍼 바이저는 마치 하드웨어인 것처럼 동작하므로 가상머신의 OS는 자신이 가상머신인 상태인지 모름
◦
반가상화 (Half Virtualization)
▪
각 가상머신에서 직접 하드웨어와 통신
▪
각 가상머신에 설치되는 OS는 가상머신인 경우 이를 인지하고 각 명령에 하이퍼 바이저 명령을 추가해서 하드웨어와 통신
•
Docker
◦
가상 머신은 컴퓨터 하드웨어를 가상화 (하드웨어 전체 추상화)
▪
하이퍼 바이저 사용, 추가 OS 필요 등 성능 저하 이슈 존재
◦
Docker는 운영체제 레벨에서 별도로 분리된 실행 환경을 제공 (커널 추상화)
▪
마치 리눅스를 처음 설치 했을 때와 유사한 실행 환경을 만들어주는 리눅스 컨테이너 기술 기반
▪
리눅스 컨테이너 기술이므로 MacOS나 Windows에 설치할 경우는 가상 머신 기반 제공
•
Java Virtual Machine
◦
가상 머신과는 다른 목적 (응용 프로그램 레벨 가상화)
◦
Java 컴파일러는 CPU Dependency를 가지지 않는 bytecode를 생성
◦
이 bytecode를 Java Virtual Machine에서 실행
◦
각 운영체제를 위한 Java Virtual Machine 프로그램이 존재