Skip to content

Files

Latest commit

 

History

History
557 lines (338 loc) · 31.2 KB

os.md

File metadata and controls

557 lines (338 loc) · 31.2 KB

운영체제

Contents

운영체제란

하드웨어와 사용자(와 각종 소프트웨어) 사이를 연결하는 소프트웨어 계층이다. 운영체제도 소프트웨어이기 때문에 컴퓨터 전원이 켜지면 메모리에 운영체제를 올리는 작업을 한다. 하지만 운영체제의 크기는 매우 크기 때문에 핵심적인 부분만 먼저 올리고 나머지 소프트웨어는 필요할 때 메모리에 올려서 사용한다. 전원이 들어오고 부터 메모리에 항상 올려져 있는 운영체제를 커널이라고 한다.

운영체제의 역할

  1. 컴퓨터의 자원(cpu, 메모리, 하드 디스크, 소프트웨어 자원)을 효율적으로 관리하는 역할
  2. 사용자 인터페이스 제공

프로세스

현재 실행중인 프로그램으로 운영체제로부너 주소공간, 파일, 메모리 등을 할당받는다. 프로세스 스택, 데이터 섹션, 을 포함한다. 운영체제는 프로세스를 생성할 때 프로세스 제어 블록(PCB)를 함께 생성한다. **PCB에 저장되는 내용 **

프로그램을 실행시킬 때 프로세스로 실행하는 이유는?

프로세스 상태

new: 프로세스가 시작되어 그 프로세스를 위한 자료구조는 생성되었으나 아직 메모리를 획득하지 못한 상태

ready: 프로세스가 CPU만 보유하면 당장 명령을 실행할 수 있는 상태

running: 프로세스가 CPU를 보유하고 기계어 명령을 실행하고 있는 상태

wait: 프로세스에게 CPU를 주어도 당장 명령을 실행할 수 없는 상태

terminated: 프로세스가 종료되었으나 운영체제가 해당 프로세스와 관련된 자료구조를 완전히 정리하지 못한 상태

PCB(Process Control Block)

운영체제가 시스템 내의 프로세스들을 관리하기 위해 프로세스마다 유지하는 정보들을 담는 커널 내 자료구조. 커널 주소공간의 data 영역에 존재한다.

image.png

PCB에 저장되는 내용들

  • process 상태 - CPU를 할당해도 되는지 여부를 결정하기 위해 필요함
  • pc값
    • 다음에 수행할 명령어의 위치를 가리킨다
  • CPU register
    • CPU 연산을 위해 현 시점에 레지스터에 어떤 값을 저장하고 있는지를 나타냄
  • CPU 스케줄링 정보
  • 메모리 관리 정보
  • 자원 사용 정보
  • 입출력 상태 정보
  • 등등

그래서, 프로레스마다 Context가 필요한 이유는 무엇일까?

그 이유는 바로 문맥교환이 일어나기 때문이다.

문맥 교환중에 CPU를 선점하고 있던 프로세스는 프로세스 문맥을 자신의 PCB에 저장하게 되고,

새롭게 CPU를 할당받을 프로세스는 PCB로부터 예전에 저장했던 자신의 문맥을 실제 하드웨어로 복원시키는 과정을 거치게 된다.

문맥 교환(Context Switching)

문맥 교환이란 하나의 사용자 프로세스로부터 다른 사용자 프로세스로 CPU의 제어권이 이양되는 과정을 말한다.

실행 상태에 있던 프로세스(A)가 입출력을 요청해야하는 경우가 생겼다고 가정해보자.

입출력을 하기 위해서 프로세스는 I/O를 요청하는 시스템 콜을 발생시키고, 프로세스는 device queue에 줄을 서게 되고 준비 상태로 상태가 변경된다.

그리고 준비 큐에 있던 다른 프로세스(B)가 CPU를 할당받아 명령을 수행하게 될 것이다.

이렇게 프로세스A에게 있던 CPU제어권이 프로세스B에게로 넘어가는 과정을 문맥 교환이라고 한다.

시스템콜이나 인터럽트로 인해 CPU제어권이 운영체제로 넘어가는 경우에도 프로세스 문맥 중 일부를 PCB에 저장하기는 하지만 이 과정을 문맥 교환이라고 하지는 않는다. 단지 하나의 프로세스가 사용자 모드에서 커널 모드로 실행 모드만 바뀌는 것 뿐이기 때문이다.

문맥 교환에 소요되는 시간은 시스템 입장에서 볼 때 일종의 오버헤드라고 할 수 있다. 따라서 타이머 인터럽트 시간을 너무 짧게하면 프로세스간 문맥 교환이 너무 자주 일어나 오버헤드가 커지게 된다.

프로세스 생성

시스템이 부팅된 후 최초의 프로세스는 운영체제가 직접 생성하지만, 그 다음부터는 이미 존재하는 프로세스를 복제하여 프로세스를 생성한다.

복제된 자식 프로세스는 프로세스 식별자를 제외하고 부모 프로세스와 똑같은 문맥을 가지게 된다. 주소공간, 레지스터 상태, PCB, 커널 스택 등 모든 문맥이 똑같다. 따라서 자식 프로세스를 생성하는 것은 부모가 아이를 낳는 것이 아니라 부모와 똑같은 나이, 똑같은 기억을 가지고 있는 복제 인간을 만드는 것과 같다.

부모 프로세스는 자신이 생성했던 모든 후손 프로세스들이 먼저 죽어야 본인이 종료될 수 있다. 부모 프로세스는 자식 프로세스를 강제로 종료시킬수도 있고, 자식 프로세스가 종료될 때 까지 wait상태로 기다릴수도 있다.

IPC(Inter-process Communication)

하나의 컴퓨터 안에서 실행중인 서로 다른 프로세스간에 발생하는 통신을 말한다.

원래 프로세스는 각각 독립적인 주소공간을 가지고 수행되고 서로의 주소공간을 참조할 수 없다. 하지만 프로세스간 통신을 통해 정보의 공유 등의 이점이 있어 프로세스간 협력 메커니즘이 생겼다.

1. 메세지 전달

커널을 통해 메세지를 전달, 수신하는 방법이다. 통신을 원하는 프로세스간에 커뮤니케이션 링크를 생성한 후 send(), receive()를 이용해 메세지를 주고받는다. 공유변수를 사용하지 않는다.

종류

  • 직접 통신: 통신하려는 프로세스에게 직접 메세지를 전송한다.
  • 간접 통신: 메세지를 메일박스 또는 포트로부터 전송받는다.

2. 공유 메모리

프로세스들이 메모리의 주소 공간의 일부를 공유하게 된다. 공유 메모리의 동기화를 보장해주어야 한다.

스레드

스레드는 한 프로세스 안에서 동작하는 실행 흐름들을 의미한다. 스레드는 프로세스 내의 공간/자원을 공유한다. (코드, 데이터 섹션, 파일, 신호 등등의 운영체제 자원)

스택을 스레드마다 독립적으로 할당하는 이유는?

스레드는 독립적인 작업이 가능해야 하기 때문이다. 스택은 되돌아갈 주소값이나 변수 등을 저장하는 곳이다. 이런 스택 공간이 독립적이어냐 독립적인 실행 context를 가질 수 있고 독립적인 실행이 가능하게 된다.

스레드도 context-switching을 하는가?

멀티 스레드 멀티 프로세스
장점 적은 memory 차지,문맥 전환이 빠름 한 프로세스가 죽어도 다른 프로세스에는 영향이 가지 않는다.
단점 공유자원이 망가질 경우 모든 스레드에 영향 많든 memory와 cpu 차지

사용자 수준 스레드와 커널 수준 스레드의 차이

사용자 수준 스레드:

장점

  • 사용자 수준 스레드는 context switch가 없다. 따라서 커널 스레드보다 오버헤드가 적다. 스레드 전환 시 커널 스케쥴러를 호출할 필요가 없기 때문.
  • 사용자 수준 스레드에서는 스레드 스케쥴러가 사용자 모드에만 존재한다.

단점

  • 프로세스 내의 한 스레드가 커널로 진입하는 순간 나머지 스레드들도 전부 정지됨. 이는 커널이 스레드의 존재를 알지 못하기에 발생하는 현상임.

커널 수준 스레드:

장점

  • 사용자 수준 스레드보다 효율적이다. 커널 스레드를 쓰면 멀티프로세서를 활용할 수 있는 장점이 있다. 사용자 스레드는 CPU가 아무리 많더라도 커널 모드의 스케쥴이 되지 않으므로 각 CPU에 효율적으로 스레드를 배당할 수 없다.

단점

  • 커널 스케쥴러를 통해 context switch가 발생한다. 이 과정에서 프로세서 모드가 사용자 모드와 커널 모드 사이를 움직이기 때문에 빈번할 수록 성능이 하락한다.

스케줄러

스케줄링

프로세스가 실행 될 때 필요한 시스템 자원을 할당해주는 작업이다.

프로세스를 스케줄링하기 위한 는 3가지가 있다.

  • Job Queue: 프로세스 상태와 무관하게 현재 시스템에 있는 모든 process들이 있다.
  • Ready Queue: CPU를 할당받기 위해 대기중인 process들이 있다. (ready 상태)
  • Divice Queue: Device I/O작업을 대기중인 process들이 있다. 각 자원마다 큐가 하나씩 존재한다. (waiting 상태)

큐는 각 프로세스의 PCB를 연결리스트 형태로 줄세우고 포인터를 활용해 순서를 정한다.

이 큐들에 process를 넣고 빼는 스케줄러도 3가지가 있다.

  • 장기 스케줄러(Job Schduler)

    어떤 프로세스를 Ready Queue에 삽입할지를 결정한다.

    new -> ready

  • 중기 스케줄러 (Swapper)

    메모리에 너무 많은 프로세스가 올라가지 않게 조절해주는 역할을 한다. 프로세스를 메모리에서 swap한다. 메모리에 적재된 프로세스의 수를 동적으로 조절한다.

    메모리에 올라와 있는 프로세스 중 일부에게서 메모리를 통째로 빼앗고 그 내용을 디스크의 swap 영역에 저장해둔다. 이 행위를 swap out이라고 한다.

    중기 스케줄러의 등장으로 인해 외부적인 이유로 프로세스 수행이 정지된 상태를 나타내는 suspend(중지)상태가 새롭게 추가되었다.(terminated와 다름)

    ready -> suspend

  • 후기 스케줄러 (CPU Schduler)

    Ready Queue에 있는 프로세스 중 어떤걸 running시킬지 결정한다.

    ready -> running

현대의 시분할 시스템용 운영체제에서는 장기 스케줄러 대신 중기 스케줄러를 두는 경우가 많다. 요즘 컴퓨터는 메모리가 커서 장기 스케줄러의 필요성이 적어졌다고 한다.

CPU Schduler 스케줄링 기법

비선점 스케줄링

프로세스가 CPU를 할당받으면 다른 프로세스가 강제로 뺏어서 사용할 수 없는(비선점) 방법이다. 그 말은 프로세스 작업이 끝날 때 까지 해당 자원을 사용한다는 것이다.

종류: FCFS, SJF, 비선점 우선순위

선점 스케줄링

우선순위가 더 높은 프로세스가 강제로 CPU를 뺏어서(선점) 사용할 수 있다. 많은 오버헤드가 생길 수 있다.

종류: Round Robin, SRT, 선점 우선순위

인터럽트

주변장치와 입출력 장치는 CPU나 메모리와 달리 인터럽트라는 메커니즘을 통해 관리된다.

그래서 인터럽트, 왜 하는거요?

그 이유는 입출력 연산이 CPU 명령 수행속도보다 현저히 느리기 때문이다.

운영체제를 악덕 사장님, CPU를 비싼 월급 주고 데려온 고오급 인력이라고 생각해보자. 악덕 사장 입장에서는 비싼돈 들여온 만큼 고오급 인력이 쉬지않고 일해서 돈값을 했으면 좋겠다고 생각할 것이다.

내 피같은 돈! 뽕을 뽑아먹겠어! (고용노동부 국번없이 1350)

그런데 아주 오래걸리는 입출력 연산을 CPU가 매번 기다린다면(월급루팡 한다면)...? 비싼 돈 주고 모셔온 CPU를 백분 활용하지 못해 운영체제 사장님은 환장할 지경.

CPU가 입출력 처리를 기다리며 쉬는 꼴을 못보는 사장님은 연산 결과가 나올 때 까지 다른 일을 시킨다. 우리 직원 뽕을 뽑아야하니까!

그리고 입출력 직원에게 자신의 업무가 완료되면 그때 CPU선배님에게 작업 완료를 알리라고 일러둔다. CPU가 다시 해당 작업도 이어서 할 수 있도록 한다.

여기서 입출력 직원이 CPU선배님에게 작업 완료를 알려주는 것이 인터럽트이다!

인터럽트란?

CPU가 프로그램을 실행하고 있을 때, 입출력 하드웨어 등의 장치나 예외상황이 발생하여 처리가 필요할 경우에 마이크로프로세서에게 알려 처리할 수 있도록 하는 것을 말한다.

인터럽트는 크게 하드웨어 인터럽트와 소프트웨어 인터럽트로 나뉜다.

하드웨어 인터럽트

하드웨어가 발생시키는 인터럽트로, CPU가 아닌 다른 하드웨어 장치가 cpu에 어떤 사실을 알려주거나 cpu 서비스를 요청해야 할 경우 발생시킨다.

소프트웨어 인터럽트

소프트웨어가 발생시키는 인터럽트이다. 소프트웨어(사용자 프로그램)가 스스로 인터럽트 라인을 세팅한다.

종류: 예외 상황, system call

인터럽트를 발생시키기 위해 하드웨어/소프트웨어는 cpu내에 있는 인터럽트 라인을 세팅하여 인터럽트를 발생시킨다. cpu는 매번 명령을 수행하기 전에 인터럽트라인이 세팅되어있는지를 검사한다.

인터럽트 과정

process A 실행 중 디스크에서 어떤 데이터를 읽어오라는 명령을 받았다고 가정해보자.

  • process A는 system call을 통해 인터럽트를 발생시킨다.
  • CPU는 현재 진행 중인 기계어 코드를 완료한다.
  • 현재까지 수행중이었던 상태를 해당 process의 **PCB(Process Control Block)**에 저장한다. (수행중이던 MEMORY주소, 레지스터 값, 하드웨어 상태 등...)
  • PC(Program Counter, IP)에 다음에 실행할 명령의 주소를 저장한다.
  • 인터럽트 벡터를 읽고 ISR 주소값을 얻어 **ISR(Interrupt Service Routine)**로 점프하여 루틴을 실행한다.
  • 해당 코드를 실행한다.
  • 해당 일을 다 처리하면, 대피시킨 레지스터를 복원한다.
  • ISR의 끝에 IRET 명령어에 의해 인터럽트가 해제 된다.
  • IRET 명령어가 실행되면, 대피시킨 PC 값을 복원하여 이전 실행 위치로 복원한다.

인터럽트와 특권 명령

명령어의 종류

CPU가 수행하는 명령에는 일반 명령특권 명령이 있다.

일반 명령은 메모리에서 자료를 읽어오고, CPU에서 계산을 하는 등의 명령이고 모든 프로그램이 수행할 수 있는 명령이다.

특권 명령은 보안이 필요한 명령으로 입출력 장치, 타이머 등의 장치를 접근하는 명령이다. 특권 명령은 항상 운영체제만이 수행할 수 있다.

kernel mode vs user mode

운영체제는 하드웨어적인 보안을 유지하기 위해 기본적으로 두가지 operation을 지원한다. kernel mode는 운영체제가 CPU의 제어권을 가지고 명령을 수행하는 모드로 일반 명령특권 명령 모두 수행할 수 있다.

하지만 user mode는 일반 사용자 프로그램이 CPU제어권을 가지고 명령을 수행하는 모드이기 때문에 일반 명령만을 수행할 수 있다.

과정을 살펴보자

위의 process A가 프로그램 명령 수행중에 디스크 입출력 명령을 읽은 경우를 생각해 보자. 사용자 프로그램은 입출력 장치에 접근하는 명령을 수행할 수 없다. user mode에서 특권 명령을 수행할 수 없기 때문이다.

이련 경우에 사용자 프로그램은 운영체제에게 시스템 콜을 통해 특권명령을 대신 수행해달라고 요청한다. 시스템 콜은 주소 공간 자체가 다른 곳(커널의 code영역)으로 이동해야 하므로 프로그램이 인터럽트 라인에 인터럽트를 세팅하는 명령을 통해 이루어진다.

시스템 콜은 커널 영역의 기능을 사용자 모드가 사용 가능하게, 즉 프로세스가 하드웨어에 직접 접근해서 필요한 기능을 사용할 수 있게 해준다.

CPU가 인터럽트 라인을 검사하고 인터럽트가 발생한 것을 감지하게 된다. 현재 수행중인 사용자 프로그램을 잠시 멈추고 CPU의 제어권을 운영체제에게 양도한다. (kernel mode) 그리고 이 때 하드웨어적으로 모드 비트가 1에서 0으로 자동으로 세팅되어 특권 명령을 수행할 수 있게 된다.

image.png

관련 용어

인터럽트 핸들러

실제 인터럽트를 처리하기 위한 루틴으로 인터럽트 서비스 루틴이라고도 한다. 운영체제의 코드 영역에는 인터럽트별로 처리해야할 내용이 이미 프로그램되어 있다.

인터럽트 벡터

인터럽드 발생시 처리해야 할 인터럽트 핸들러의 주소를 인터럽트 별로 보관하고 있는 테이블이다.

PCB(Process Control Block)

커널의 데이터 영역에 존재하며 각각의 프로세스마다 고유의 PCB가 있다. 인터럽트 발생 시 프로세스의 어느 부분이 수행중이었는지를 저장한다. (수행중이던 memory 주소, 레지스터값, 하드웨어 상태 ...)

시스템 콜

시스템 콜의 유형

시스템 콜은 다섯 가지의 중요한 범주로 나눌 수 있다. 프로세스 제어, 파일 조작, 장치 조작, 정보 유지보수, 통신과 보호.

  • 프로세스와 관련된 시스템 호출

    • 프로세스 제어용 . exec : 자신을 수행 가능한 다른 프로세스로 대치 수행 . fork : 현재의 프로세스 이미지를 복사하고 child 프로세스를 만듬 . wait
    • pipe : 파이프
    • signal : 소프트웨어 인터럽트 또는 시그널
    • exit : 프로세스 종료
    • getuid, setuid ... : 사용자 및 그룹 id 접근
  • 표준 화일(장치)에 대한 입출력 시스템 호출

    • open( ), close( ), read( ), write( ), lseek( ), create( ), ...
  • 소켓 기반의 입출력 시스템 호출

    • socket(), bind(), listen(), accept(), connect(), ...

주소 바인딩

프로세스는 실행을 위해 메모리에 적재되면 프로세스를 위한 독자적인 주소공간이 생긴다. 이 주소를 논리적 주소라고 한다. 논리적 주소는 각 프로세스마다 독립적으로 할당된다.

왜 프로세스는 논리적 주소를 사용할까?

CPU가 프로세스의 작업을 수행하기 위해서 프로세스의 논리적 주소를 참조하게 된다. 논리적 주소만으로는 실제 메모리의 주소를 알 수 없기 때문에 논리 주소를 물리적 메모리로 열결시키는 작업이 필요하다. 이 작업을 주소 바인딩이라고 한다.

주소 바인딩에는

  • 컴파일 타임 바인딩
  • 로드 타임 바인딩
  • 실행 시간 바인딩

이렇게 세가지 바인딩 방식이 있다. 세 바인딩의 기준은 물리적 주소가 언제 결정되느냐에 따라서 결정된다.

컴파일 타임 바인딩

말 그대로 컴파일 할 때 물리적 메모리 주소가 결정되는 주소 바인딩이다. 프로그램의 물리적 주소를 변경하고 싶으면 다시 컴파일해야 한다.

로드 타임 바인딩

프로그램의 실행이 시작될 때 물리적 주소가 결정된다. 이 바인딩에서는 로더가 메모리 주소를 부여하고 프로그램이 종료될 때 까지 물리주소가 고정된다.

실행 시간 바인딩(run time binding)

프로그램이 실행한 후에도 물리적 주소가 변경될 수 있는 바인딩 방식이다. 런타임 바인딩에서는 CPU가 주소를 참조할 때마다 해당 데이터가 물리적 메모리의 어느 위치에 존재하는지 주소 매핑 테이블을 이용해 주소 바인딩을 점검한다. 그리고 주소 매핑 테이블 뿐 만 아니라 기준 레지스터, 한계 레지스터, MMU(Memeoty Management Unit이 필요하다. 런타임 바인딩은 메모리에 프로세스의 주소공간이 연속적으로 적재되어 있음을 가정한다.

  • 기준 레지스터: 프로세스의 물리적 메모리의 시작 주소를 가지고 있다.
  • 한계 레지스터: 현재 CPU에서 수행중인 프로세스의 논리적 주소의 최대값, 프로세스의 크기를 가지고 있다.
  • MMU: 논리적 주소를 물리적 주소로 메핑해주는 하드웨어

image.png

MMU 동작 방식

재배치 레지스터에는 현재 CPU에서 수행중인 프로세스의 물리적 메모리 시작 주소가 저장되어 있다. CPU가 논리적 주소 245에 있는 데이터를 요청하게 되면 재배치 레지스터에 저장된 물리적 시작 주소와 해당 논리적 주소를 더한다. 그렇게해서 실제 메모리의 8245에 있는 데이터를 꺼내오면 된다.

그렇다면 한번 생각해보자🤔 프로세는 고유한 주소공간을 가지고 있다. 그리고 논리적 주소값은 프로세스마다 독립적으로 할당된다고 하였다. 프로세스A에도 100번 논리 주소가, 프로세스B에도 100번 논리주소가 있다는 말이다. 그렇지만 프로세스A의 100번 논리주소에 매핑되는 실제 물리적 주소와 프로세스B에 매핑되는 실제 물리적 주소는 다를 것이다. 따라서 MMU기법에서는 문맥교환이 일어날 때 마다 재배치 레지스터의 값을 바뀌는 프로세스에 해당되는 값으로 재설정을 해주어야 한다.

한계 레지스터가 필요한 이유

MMU 방식에서는 기준레지스터값 + 논리적 주소값을 통해서 주소 바인딩을 한다. 만약 해당 값이 해당 프로세스의 주소범위를 넘어가는 값이 된다면 어떻게 될까? 프로세스가 접근해서는 안되는 영역을 접근할 가능성이 생긴다. 이런 문제점을 방지하기 위해서 한계레지스터를 사용하는 것이다. 한계 레지스터에 최대 논리적 주소값을 저장하고 CPU가 논리적 주소를 요청할 때 마다 한계 레지스터 값보다 작은 값인지를 검사하게 된다.

⚙여러가지 메모리 관리 기법

동적 로딩

프로세스가 실행될 때 프로세스 주소공간 전체를 메모리에 올리지 않고, 필요한 부분만 그때 그때 메모리에 적재하는 방식

  • 메모리 효율적 사용 가능
  • 프로스램 자체에서 구현 가능

동적 연결

linking: 소스코드를 컴파일하여 이미 컴파일된 라이브러리 파일들과 묶어(linking) 하나의 실행파일을 생성하는 것

동적 연결은 컴파일한 소스코드와 라이브러리파일을 바로 연결하지 않고 프로그램이 실행되고 라이브러리 함수를 호출할 때 라이브러리 파일과 linking하는 방식.

  • 실행 파일에 라이브러리 코드가 포함되지 않는다.
  • 공통으로 사용하는 라이브러리를 메모리에 한번만 적재해서 메모리 효율 ↑
  • 운영체제의 지원 필요

스와핑

메모리에 올라온 프로세스의 주소공간 전체를 디스크의 swap 영역으로 이동시키는 것을 말한다.

swap 영역은 backing store라고도 부르고, 디스크 내에 파일 시스템과는 별도로 존재하는 영역이다.

스와핑을 하는 이유는 메모리에 너무 많은 프로세스가 적재되어서 시스템 성능이 떨어지게 되면 그중 당장 사용하지 않는 몇개의 프로세스를 스왑 영역으로 내쫒아 메모리공간을 확보하기 위해서이다.

이 작업은 중기 스케줄러가 담당하여 처리한다.

image.png

동기화란?

공유 자원에 대하여 동시에 접근하는 프로세스/스레드들로 인해 발생하는 문제를 해결하기 위해 행하는 방식.

교착 상태(데드락)의 4가지 조건

  1. 상호배제(Mutual exclusion) : 프로세스들이 필요로 하는 자원에 대해 배타적인 통제권을 요구한다.
  2. 점유대기(Hold and wait) : 프로세스가 할당된 자원을 가진 상태에서 다른 자원을 기다린다.
  3. 비선점(No preemption) : 프로세스가 어떤 자원의 사용을 끝날 때까지 그 자원을 뺏을 수 없다.
  4. 순환대기(Circular wait): 각 프로세스는 순환적으로 다음 프로세스가 요구하는 자원을 가지고 있다.

이 조건 중 한 가지라도 만족하지 않으면 교착 상태는 발생하지 않는다. 순환대기 조건은 점유대기 조건과 비선점 조건을 만족해야 성립하는 조건이므로 위 4가지 조건은 서로 완전히 독립적이지 않다.

해결 방법

  1. 교착 상태의 예방
  2. 교착 상태의 회피
  3. 교착 상태의 무시
  4. 교착 상태의 발견

운영체제의 메모리 관리

운영체제는 자원의 효율적인 관리를 도맏아 하는 소프트웨어이다. 따라서 운영체제는 어떤 프로그램에 얼마만큼의 메모리를 할당해야 할지를 결정해야한다.

메모리 할당 방법에는

  • 균등 할당
  • 비례 할당
  • 우선순위 할당

세가지 방법이 있다. 균등할당은 프로세스마다 동일한 메모리를 할당하는 방식이고, 비례할당은 프로세스의 크기에 비례하게 메모리를 할당하는 방식, 우선순위 할당은 우선순위가 높은 프로세스에게 더 많은 메모리를 할당하는 방식이다.

또한 운영체제는 프로세스를 통째로 메모리에 올릴 수 있지만 CPU에서 당장 수행해야 할 부분만 메모리에 올리고 나머지는 디스크의 swap 영역에 두어 메모리를 효율적으로 사용한다.

가상 메모리

운영체제는 프로그램이 자기 자신만의 가상 메모리를 사용하는 것처럼 가정해 프로그램 하는 것을 지원한다. 가상 메모리 주소 공간은 논리적 주소로서 모든 프로그램마다 0부터 시작하게 된다. 즉, 가상메모리는 프로세스마다 논리적 주소공간을 가지고 이 주소공간의 일부는 물리적 메모리에 적재되고 일부는 스왑영역에 존재한다.

장점

  • 메모리 사용량 감소 (프로세스 일부만 올리니까)
  • 입출력 오버헤드 감소 ( 일부만 디스크 -> 메모리 입출력 하니까)
  • 시스템이 더 많은 프로세스를 수용할 수 있다.
  • 프로그램이 물리적 메모리의 용량 제약에서 자유롭다 (메모리보다 큰 프로그램 실행 가능)

가상메모리 기법은 프로세스의 주소공간을 적재하는 단위에 따라 요구 페이징 기법요구 세그멘테이션 기법 두개로 나눌 수 있다.

요구 페이징 기법

페이지 단위로 프로세스의 주소공간을 메모리에 적재하며 당장 사용될 페이지만을 메모리에 적재한다.

페이지 부재

CPU에서 요청한 페이지가 현재 메모리에 없어 유효-무효 비트가 무효로 세팅되어 있는 경우를 말한다. 페이지 부재 발생 시 페이지를 디스크에서 읽어와야 하는데 이 과정에서 막대한 overhead가 발생한다. 따라서 요구 페이징 기법은 페이지 부재 발생률이 성능에 큰 영향을 끼친다.

페이지 부재 시 동작 과정

  1. MMU(Memory Management Unit)가 페이지 부재 트랩을 발생시킨다. (트랩=소프트웨어 인터럽트)
  2. 인터럽트로 인해 커널모드로 전환되어 OS의 페이지 부재 처리 루틴이 호출된다.
  3. 해당 부재 페이지의 보호비트를 참조해 접근이 가능한지 체크한다.
  4. 물리메모리에 비어있는 프레임을 할당받고 그곳에 페이지를 읽어온다.
  5. 페이지를 읽어오는 동안 프로세스는 wait상태가 된다.
  6. 디스크 입출력 완료시 인터럽트를 발생시키고 해당 페이지의 유효-무효 비트를 유효로 세팅한다

페이지 교체

페이지 부재 발생시 메모리에 해당 페이지를 적재해야 하는데 이때 메모리가 꽉찼다면 어떡해야 할까?? 이때는 메모리에 있는 페이지중 가장 쓸모 없어보이는 것을 골라 스왑 영역으로 쫒아내고 그 자리에 페이지 부재된 페이지를 적재해야 한다. 이 과정이 페이지 교체이다.

교체할 페이지를 선정할 때 교체 대상이 될 프레임의 범위에 따라 전역 교체지역 교체로 나눌 수 있다. 전역교체 방법은 모든 페이지 프레임이 교체 대상이 될 수 있는 방법이다. 지역 교체 방법은 현재 수행중인 프로세스에게 할당된 페이지 프레임 내에서만 페이지 교환을 하는 방법이다.

페이지 교체 알고리즘

  • 최적 교체(OPT) 알고리즘
  • FIFO
  • LRU(Least Recently Used)
  • LFU(Least Frequently Used)
  • NUR(Not Used Recently)

최적 페이지 교체 알고리즘

각 페이지의 호출 순서를 미리 알고있는 전제 하에 알고리즘을 운영 가장 먼 미래에 호출될 페이지와 교체한다. 실제로 구현할수 없다.

LRU

가장 과거에 호출되었던 페이지와 교체한다. 시간 지역성을 활용

최근에 참조된 페이지가 다시 참조될 가능성이 높다

LFU

가장 적은 횟수로 참조된 페이지와 교체한다. Incache-LFU, Perfect-LFU

NUR(클럭 알고리즘)

LRU 근사 알고리즘이다. LRU처럼 오랫동안 참조하지 않은 페이지중 하나를 선택하지만 가장 오래된 페이지라는 보장은 없다. 하드웨어적 지원을 통해 알고리즘을 운영해 오버헤드를 줄임 페이지 프레임의 참조 비트를 조사해서 참조비트가 0인 페이지를 찾으면 그 페이지와 교체한다

스레싱

프로세스의 처리 시간보다 페이지 교체에 드는 시간이 더 많아져 CPU이용률이 떨어지는 현상을 말한다. 다중프로그래밍정도가 높아지면 어느정도 까지는 CPU이용률이 오르지만, 한계치를 넘으면 스레싱이 발생하고 CPU이용률이 급감한다.

다중프로그래밍정도: 메모리에 동시에 올라가 있는 프로세스의 수

해결책

  • 다중프로그래밍정도를 적정 수준으로 유지한다.
  • 페이지 부재 빈도를 조절한다
  • working set을 유지한다
  • 일부 프로세스를 중단한다