
운영체제 (Operating System)란?
하드웨어 자원을 관리하는 소프트웨어: 컴퓨터의 하드웨어 자원을 효율적으로 관리하고 제어하는 역할을 수행합니다.
인터페이스 역할: 운영체제는 응용 프로그램과 하드웨어 간의 상호작용을 조정하고 관리합니다.
커널 (Kernel)이란?
커널은 운영체제의 핵심 부분으로, 항상 필요한 운영체제 기능을 수행하기 위해 메인 메모리에 상주하는 부분을 의미합니다.
메모리 관리: 커널은 메모리 공간을 효율적으로 관리하고, 프로세스들이 메모리를 공유하고 충돌하지 않도록 합니다.
프로세스 관리: 프로세스를 생성, 제어, 종료하는 역할을 수행하며, 프로세스 간의 통신과 스케줄링을 조정합니다.
파일 시스템 관리: 파일의 생성, 읽기, 쓰기, 삭제 등 파일 시스템의 기능을 제공합니다.
입출력 관리: 입출력 장치와의 상호 작용을 관리하며, 데이터의 입출력을 조절합니다.
시스템 콜 제공: 응용 프로그램이 운영체제 기능을 활용할 수 있도록 시스템 콜을 제공합니다.
메모리의 구조
메모리는 다음과 같이 여러 영역으로 나눌 수 있습니다.
코드 영역 (텍스트 영역):
코드가 저장되는 영역입니다.데이터 영역 (Static 영역):
전역 변수와 정적 변수가 저장되는 영역입니다.힙 영역 (Heap):
동적 메모리 할당 영역입니다.스택 영역 (Stack):
지역 변수와 매개변수가 저장되는 영역입니다.힙 영역과 스택 영역의 차이
new 연산자나 malloc 함수로 할당되며, 명시적으로 해제되기 전까지 메모리에 유지됩니다.스택 영역: 스택은 힙에 비해 접근 및 소멸이 빠르며 함수 호출 및 반환과 관련하여 자동으로 관리됩니다.
힙 영역: 힙은 스택에 비해 접근 및 소멸이 느리며, 개발자가 직접 메모리를 할당하고 해제해야 합니다. 그러므로 주의가 필요합니다.
힙 영역을 너무 크게 잡는 문제점
메모리 낭비:
Garbage Collection (GC) 오버헤드:
메모리 관리 어려움:
일반적으로 힙 영역은 필요한 만큼만 할당하고, 필요할 때 동적으로 확장하는 방식으로 관리됩니다. 예를 들어, Java의 JVM(Java Virtual Machine)은 힙 영역을 처음부터 크게 설정하지 않고, Heap 영역이 꽉 찼을 때 GC를 진행한 후 Heap 영역을 확장합니다. 이렇게 함으로써 메모리 사용을 효율적으로 관리하고 GC의 오버헤드를 최소화할 수 있습니다.
프로세스
프로세스는 메인 메모리(주기억장치)에 적재되어 실행되는 프로그램을 의미합니다.
각 프로세스는 PCB(Process Control Block), 코드(Code), 데이터(Data), 힙(Heap), 스택(Stack) 영역을 갖습니다.
프로세스끼리는 각각의 영역을 독립적으로 갖기 때문에 별다른 동기화 작업이 필요하지 않습니다.
각 프로세스는 독립된 메모리 공간을 사용하므로 컨텍스트 스위칭(Context Switching) 비용이 큽니다.
프로세스는 생성 및 관리에 비용이 많이 들며, 생성 시간이 상대적으로 길다.
한 프로세스에서 오류가 발생하더라도 다른 프로세스에 영향을 주지 않습니다.
쓰레드
쓰레드(Thread)는 한 프로세스 내의 실행 단위, 실행의 흐름을 의미합니다.
쓰레드는 스택(Stack) 영역만을 별도로 갖고, 나머지 영역(code, data, heap)에 대해서는 해당 쓰레드를 포함한 프로세스의 자원을 공유합니다.
쓰레드가 공유 자원에 접근할 때는 동기화 작업이 필요합니다.
스택 영역 외부를 공유하므로 컨텍스트 스위칭 비용이 상대적으로 적습니다.
쓰레드는 프로세스보다 가볍기 때문에 생성 시간이 더 짧습니다.
한 쓰레드에서 오류가 발생하면, 나머지 프로세스 내의 쓰레드에 영향을 줄 수 있습니다.
프로세스와 쓰레드의 차이
독립성:
동기화:
자원 공유:
성능:
프로세스와 쓰레드는 각각의 장단점이 있으며, 사용 목적에 따라 선택되어야 합니다. 프로그램의 병렬 처리와 자원 공유가 필요한 경우 쓰레드를 사용하고, 독립적인 프로그램 실행이 필요한 경우 프로세스를 사용할 수 있습니다.
컨텍스트 스위칭(Context Switching)이란?
컨텍스트 스위칭은 여러 프로세스를 처리해야 할 때, 현재 실행 중인 Task(프로세스 또는 스레드)의 상태를 저장하고, 다음에 실행할 Task의 상태를 읽어 레지스터에 적재하는 과정을 의미합니다. 이 과정을 통해 CPU는 여러 프로세스 간에 작업을 전환할 수 있습니다.
효율적인 CPU 활용:
다중 작업 처리:
현재 프로세스의 상태 저장:
다음 프로세스 선택:
다음 프로세스의 상태 복원:
프로세스 실행 재개:
프로세스 제어 블록 (PCB)란?
프로세스 제어 블록(PCB)은 운영체제 내에서 프로세스를 관리하기 위한 중요한 자료 구조입니다. 각 프로세스마다 하나의 PCB가 할당되며, PCB에는 프로세스와 관련된 중요한 정보를 저장하고 있습니다.
프로세스 식별자 (Process ID, PID):
프로세스 상태:
프로그램 카운터:
CPU 레지스터:
CPU 스케줄링 정보:
메모리 관리 정보:
입출력 상태 정보:
어카운팅 정보:
컨텍스트 스위칭(Context Switching)이 발생할 때, 현재 실행 중인 프로세스의 상태는 해당 프로세스의 PCB에 저장됩니다. 그리고 다음에 실행할 프로세스의 PCB에서 상태 정보를 불러와서 작업을 이어나가게 됩니다. 이렇게 PCB를 통해 프로세스 간에 상태를 전환하고 관리합니다.
PCB는 각 프로세스마다 고유하며 중요한 정보를 담고 있어서 보호된 메모리 영역에 위치하며, 운영체제의 핵심 역할 중 하나입니다. 이를 통해 운영체제는 다중 프로세스를 효과적으로 관리하고 실행할 수 있습니다.
크롬 브라우저의 탭은 프로세스인가요? 쓰레드인가요?
크롬 브라우저에서 각 탭은 별도의 프로세스로 실행됩니다. 이것을 "프로세스 기반 멀티태스킹"이라고 합니다. 이러한 구조는 여러 가지 이점을 제공합니다.
안정성: 각 탭은 독립된 프로세스에서 실행되므로 하나의 탭에서 오류가 발생해도 다른 탭에는 영향을 미치지 않습니다. 이것이 브라우저 크래시를 방지하고 사용자 경험을 향상시키는 데 도움이 됩니다.
보안: 각 탭은 분리된 프로세스에서 실행되므로 다른 탭의 데이터에 접근하기 어려워 보안을 강화합니다.
성능: 멀티프로세스 아키텍처는 여러 CPU 코어를 활용하여 병렬로 작업을 수행할 수 있어 빠른 브라우징을 가능하게 합니다.
멀티 쓰레드 vs. 멀티 프로세스
멀티 쓰레드는 하나의 프로그램 안에서 여러 작업을 효율적으로 해결할 수 있으며, Context Switching 시에 Stack 영역만 초기화하면 되기 때문에 빠르게 작업을 전환할 수 있습니다. 또한, 프로세스를 생성할 때 자원을 할당하는 오버헤드가 적어 자원을 효율적으로 관리할 수 있는 장점이 있습니다.
그러나 쓰레드 간 동기화와 오류 처리에 주의해야 하며, 안정성을 보장하기 위한 추가 작업이 필요할 수 있습니다. 선택은 상황과 요구사항에 따라 달라지므로, 프로젝트의 성격과 목표에 따라 쓰레드 또는 프로세스를 선택해야 합니다.
쓰레드마다 독립적으로 할당되는 요소
멀티 쓰레드 환경에서의 주의해야 할 점
멀티 쓰레드 환경에서 작업할 때에는 다음과 같은 주의사항을 고려해야 합니다:
동기화 (Synchronization):
데드락 (Deadlock) 및 교착 상태 (Starvation) 방지:
공유 자원 접근 제한:
Race Condition 방지:
메모리 일관성 (Memory Consistency):
동기 vs 비동기
동기는 요청과 그 결과가 동시에 일어난다는 약속입니다. 즉, 어떤 작업을 요청하면 그 작업이 완료되어 결과가 반환될 때까지 대기합니다. 이때 결과가 주어지기 전까지는 다른 작업을 진행하지 않습니다.
A 함수가 B 함수를 호출하면, B 함수의 실행이 끝나야만 A 함수가 다음 작업을 수행합니다. 이는 설계가 간단하고 직관적이지만, 결과를 기다리는 동안 아무런 다른 작업을 수행하지 못하고 대기해야 합니다.
비동기는 요청과 결과가 동시에 발생하지 않을 것이라는 약속입니다. 요청한 작업이 완료되면 결과를 반환하는 대신, 다른 작업을 수행하다가 결과가 준비되면 이를 처리하는 방식입니다. 이로써 자원을 효율적으로 활용할 수 있습니다.
A 함수가 B 함수를 호출하면 B 함수의 실행은 백그라운드에서 비동기적으로 진행됩니다. A 함수는 결과를 기다리지 않고 다른 작업을 수행할 수 있습니다. 그러다가 B 함수의 결과가 준비되면 B가 A에게 callback을 통해 알려주고, A는 결과를 처리합니다.
비동기 방식은 복잡할 수 있지만, 결과를 기다리는 동안 다른 작업을 수행할 수 있어서 효율적인 자원 활용을 가능하게 합니다. 이는 네트워크 호출, 파일 입출력 등 시간이 걸리는 작업에서 특히 유용합니다.
프로세스의 종류
자식 프로세스 (Child Process):
fork 함수를 사용하여 부모 프로세스로부터 새로운 자식 프로세스를 생성한 상태입니다.데몬 프로세스 (Daemon Process):
고아 프로세스 (Orphan Process):
좀비 프로세스 (Zombie Process):
Race Condition과 Critical Section
Race Condition(경쟁상태)은 두 개 이상의 쓰레드나 프로세스가 공유 자원에 접근할 때 서로 경쟁하며 예상치 못한 동작을 발생시키는 현상입니다. 이러한 상황은 데이터 일관성과 무결성을 깨뜨릴 수 있습니다.
Critical Section(임계영역)은 Race Condition이 발생할 수 있는 부분을 가리키며, 여러 쓰레드 또는 프로세스가 공유 자원을 동시에 접근하는 부분입니다.
Race Condition을 방지하고 Critical Section을 안전하게 관리하기 위해 상호배제(Mutual Exclusion) 메커니즘을 사용합니다. 이것은 다음과 같이 동작합니다:
임계영역 진입 (Enter Critical Section):
임계영역에서 작업 수행 (Perform Operations):
임계영역 빠져나옴 (Exit Critical Section):
상호배제를 구현하기 위한 여러 방법이 있으며, 가장 일반적인 방법은 뮤텍스(Mutex)와 세마포어(Semaphore)를 사용하는 것입니다. 이러한 메커니즘은 쓰레드나 프로세스가 공유 자원을 안전하게 접근하도록 보장하며, Race Condition을 방지하여 데이터 일관성을 유지합니다.
Deadlock(교착상태)란?
Deadlock은 두 개 이상의 프로세스나 스레드가 서로 자원을 기다리면서 무한히 대기하는 상태를 의미합니다. Deadlock이 발생하려면 네 가지 조건이 동시에 충족되어야 합니다:
교착상태를 해결하기 위해서는 위에서 언급한 네 가지 조건 중 하나 이상을 제거해야 합니다.
예방 (Prevention):
회피 (Avoidance):
회복 (Recovery):
식사하는 철학자 문제
"식사하는 철학자 문제"에서 Deadlock은 다음 조건들이 동시에 충족될 때 발생합니다:
점유대기 (Hold and Wait): 철학자는 이미 한 손에 포크를 들고 있으면서 다른 손에 포크를 얻으려고 대기합니다.
비선점 (Non-preemption): 철학자가 이미 어떤 포크를 들고 있으면 다른 철학자가 그 포크를 빼앗을 수 없습니다.
환형대기 (Circular Wait): 모든 철학자가 오른쪽 포크를 얻기 위해 서로를 기다립니다.
상호배제 (Mutual Exclusion): 한 번에 하나의 철학자만이 포크를 얻을 수 있어야 합니다.
"식사하는 철학자 문제"를 해결하기 위해서는 다음과 같은 방법들을 사용할 수 있습니다:
예방 (Prevention):
회피 (Avoidance):
강제로 포크를 뺏기 (Force Fork Releasing):
상호배제 원칙 완화 (Relax Mutual Exclusion):
뮤텍스 (Mutex)
뮤텍스는 "상호 배제"라고도 불리며, 다음과 같은 특징을 가집니다:
뮤텍스는 주로 공유 자원에 대한 동시 접근을 제어하기 위해 사용됩니다.
세마포어 (Semaphore)
세마포어는 "동시 접근 제어"를 위한 도구로, 다음과 같은 특징을 가집니다:
세마포어는 이진 세마포어와 카운팅 세마포어로 나누어집니다:
CPU Scheduling (CPU 스케줄링)이란?
CPU Scheduling은 Ready Queue(준비 큐)에 있는 프로세스 중에서 다음에 CPU를 할당할 프로세스를 선택하는 알고리즘을 의미합니다. 이것은 다중 프로세스 환경에서 CPU 자원을 효율적으로 관리하기 위해 사용됩니다.
First Come First Served (FCFS):
Shortest Job First (SJF):
Highest Response Ratio Next (HRRN):
Round Robin (RR):
Shortest Remaining Time First (SRTF):
Multilevel Feedback Queue (다중 레벨 피드백 큐):
콘보이 현상 (Convoy Effect)
콘보이 현상은 작업 시간이 긴 프로세스가 먼저 큐에 도착하여 다른 프로세스의 실행 시간이 전부 늦춰져 효율성을 떨어뜨리는 현상을 말합니다. 이는 주로 CPU 스케줄러의 선택 방식에 의해 발생합니다.
FCFS 스케줄링은 비선점형 스케줄링으로, 먼저 큐에 도착한 작업부터 순차적으로 실행합니다. 이 때, 콘보이 현상이 발생할 수 있습니다. 예를 들어, 하나의 프로세스가 긴 시간 동안 CPU를 점유하는 경우, 그 이후에 도착하는 프로세스들은 기다려야 하므로 실행이 지연됩니다. 이로 인해 효율성이 저하될 수 있습니다.
콘보이 현상을 해결하기 위해서는 다양한 스케줄링 알고리즘이 사용됩니다. 예를 들어, Round Robin 스케줄링은 시간 할당량을 설정하여 각 프로세스에 동등한 실행 기회를 부여하고, 긴 작업 시간을 가진 프로세스가 다른 프로세스를 지연시키는 현상을 완화합니다.
또한, 우선순위 기반 스케줄링은 각 프로세스에 우선순위를 부여하여 중요한 작업이 먼저 실행되도록 하는 방식으로, 콘보이 현상을 방지하는 데 도움이 됩니다.
이렇게 CPU 스케줄러 알고리즘을 효과적으로 선택하고 구성함으로써 콘보이 현상을 최소화하고 시스템의 성능을 향상시킬 수 있습니다.
CPU 성능 척도
CPU Utilization(이용률):
Throughput(처리량):
Turnaround Time(소요시간, 반환시간):
Waiting Time(대기시간):
Response Time(응답시간):
선점과 비선점
선점 방식은 CPU 스케줄링에서 사용되는 방식 중 하나로, 특정 프로세스가 실행 중이더라도 CPU 할당을 뺏어 다른 프로세스에게 할당할 수 있는 방식입니다. 이 방식은 다음과 같은 상황에서 CPU를 다른 프로세스로 넘길 수 있습니다:
System Call: 특정 프로세스가 시스템 호출(System Call)을 요청하면 CPU가 해당 호출을 처리하기 위해 다른 프로세스에게 넘어갈 수 있습니다.
Time Quantum: 각 프로세스는 일정한 시간 할당량(타임 슬라이스)을 받고, 이 시간이 경과하면 CPU를 다른 프로세스에게 양보하게 됩니다.
Interrupt: 하드웨어나 소프트웨어 인터럽트가 발생하면 현재 실행 중인 프로세스는 중단되고, 인터럽트 처리를 위한 코드가 실행됩니다. 이후 다른 프로세스로 CPU가 전환됩니다.
비선점 방식은 특정 프로세스가 실행 중이면 그 프로세스가 끝날 때까지는 CPU를 다른 프로세스에게 양보하지 않는 방식입니다. 즉, 한 번 CPU를 할당받은 프로세스는 자발적으로 CPU를 양보하지 않는 한 계속 실행됩니다.
선점 방식과 달리, 비선점 방식에서는 프로세스가 자발적으로 끝나야만 CPU가 다른 프로세스로 넘어갑니다.
이러한 방식은 실시간 시스템에서 사용되거나 특정 상황에서 프로세스의 우선순위를 고려할 때 유용합니다.
동시성과 병렬성
동시성은 멀티 프로그래밍 (Multi-Programming) 환경에서 나온 개념으로, 주기억장치에 여러 프로세스를 적재하여 Context Switching을 통해 동시에 실행되는 것 처럼 보이게 하는 것을 의미합니다. 그러나 실제로는 동시에 실행되는 것이 아닌 번갈아가며 실행됩니다. 이 개념은 싱글 코어(CPU)에서 멀티스레드를 동작시키기 위한 방식으로 사용됩니다.
병렬성은 멀티 프로세싱 (Multi-Processing) 환경에서 나온 개념으로, 실제로 동시에 여러 프로세스를 병렬적으로 실행하는 방식을 의미합니다. 이를 위해서는 CPU가 멀티코어를 가지고 있어야 합니다.
Interrupt(인터럽트)란?
Interrupt(인터럽트)는 프로그램을 실행하고 있는 도중에 입출력 요청이나 예외 상황과 같은 이벤트가 발생하면, 현재 실행 중인 프로그램을 일시적으로 멈추고 CPU가 해당 작업을 처리하도록 하는 메커니즘입니다. 이는 컴퓨터 시스템이 다양한 작업을 동시에 처리하고 효율적으로 관리하기 위한 중요한 개념 중 하나입니다.
입출력(I/O) 처리: 사용자가 키보드로 입력하거나 디스크에서 데이터를 읽거나 쓸 때와 같은 입출력 작업을 비동기적으로 처리합니다. CPU가 직접 대기하지 않고 다른 작업을 수행할 수 있게 합니다.
예외 처리: 프로그램 실행 중에 예외 상황(예: 0으로 나누기)이 발생하면 이를 처리하고 예외 상황을 해결하거나 적절한 조치를 취할 수 있도록 합니다.
타이머 인터럽트: 일정 시간마다 발생하여 운영체제의 스케줄러에 의해 다른 프로세스로 CPU를 전환시켜 다중 작업을 지원합니다.
시스템 콜 (System Call)이란?
시스템 콜은 사용자나 응용 프로그램이 운영체제 커널에서 제공하는 기능을 사용하기 위한 인터페이스입니다. 이러한 인터페이스를 통해 운영체제는 커널에서 제공하는 서비스를 사용할 수 있도록 허용하면서 컴퓨터 자원을 보호합니다. 사용자나 응용 프로그램은 시스템 콜을 통해 운영체제의 기능을 호출하고, 운영체제는 이러한 호출을 처리합니다.
커널 접근: 시스템 콜은 사용자 영역에서 커널 영역으로 전환을 수행합니다. 이렇게 함으로써 사용자 프로세스가 직접 커널에 접근하지 않고, 커널이 제공하는 서비스를 사용할 수 있습니다.
자원 보호: 시스템 콜을 통해 운영체제는 컴퓨터 자원을 효과적으로 보호합니다. 사용자나 응용 프로그램은 직접 자원에 접근할 수 없고, 운영체제를 통해 접근해야 합니다.
서비스 제공: 운영체제는 시스템 콜을 통해 다양한 서비스를 제공합니다. 이 서비스에는 파일 관리, 프로세스 관리, 메모리 관리, 네트워크 통신 등이 포함됩니다.
메모리의 종류
메모리의 다양한 종류가 존재하는 이유는 접근 속도와 저장 용량에 따른 차이 때문입니다. 여기에 몇 가지 이유가 있습니다:
접근 속도: 메모리의 종류에 따라 접근 속도가 다릅니다. CPU에 가까운 레지스터와 캐시는 매우 빠른 속도로 데이터에 접근할 수 있어 프로세서의 성능을 향상시킵니다.
용량: 레지스터와 캐시는 용량이 제한적이며 주로 중요한 데이터나 명령어를 저장합니다. 주기억장치는 용량이 더 크지만 상대적으로 느립니다.
영구 저장: 보조기억장치는 데이터를 영구적으로 보존할 수 있어, 시스템이 종료되어도 정보가 유지됩니다.
비용: 메모리 종류에 따라 비용도 다릅니다. 레지스터와 캐시는 빠르지만 비용이 높고, 주기억장치는 비교적 저렴합니다.
메모리 관리의 필요성
각각의 프로세스는 독립된 메모리 공간을 갖기 때문에 다른 프로세스의 메모리 영역에 접근할 수 없습니다. 이러한 분리된 메모리 공간은 다음과 같은 이유로 메모리 관리가 필요합니다:
보안: 프로세스 간의 상호 간섭을 방지하고, 각 프로세스가 자신의 데이터를 안전하게 보호하기 위해 메모리 공간을 분리합니다.
효율성: 각 프로세스가 필요한 메모리 공간을 독립적으로 할당받아 작업을 수행하므로 효율적인 멀티태스킹을 지원합니다.
가상 메모리: 물리적인 RAM 크기보다 큰 메모리 공간을 프로세스에 제공하여 더 많은 프로세스를 동시에 실행할 수 있게 합니다.
메모리 관리 전략
운영체제는 다양한 전략을 사용하여 메모리를 관리합니다. 일반적인 메모리 관리 전략으로는 다음과 같은 것들이 있습니다:
Swapping: 가장 오래동안 사용되지 않은 프로세스나 프로세스의 일부를 디스크로 스왑하여 더 많은 공간을 확보합니다. 필요할 때 디스크에서 다시 가져옵니다.
페이징 (Paging): 물리적 메모리와 논리적 메모리를 일정한 크기의 페이지로 나누고, 페이지 단위로 메모리를 할당합니다. 페이지 교체 알고리즘을 사용하여 필요한 페이지를 물리적 메모리에 올립니다.
세그멘테이션 (Segmentation): 논리적 메모리를 여러 세그먼트로 나누고 각 세그먼트를 독립적으로 할당합니다. 이는 프로세스의 논리적 구조를 반영하며 메모리 할당을 관리합니다.
고정 길이 할당 / 가변 길이 할당: 메모리 공간을 고정 길이 블록 또는 가변 길이 블록으로 나누어 관리합니다. 고정 길이 할당은 메모리의 파편화 문제를 줄이지만, 가변 길이 할당은 더 효율적으로 메모리를 사용할 수 있습니다.
압축 (Compression): 더 많은 프로세스를 메모리에 유지하기 위해 압축 기술을 사용하여 메모리 공간을 압축합니다. 필요할 때 압축을 해제하여 사용합니다.
메모리의 fit의 종류
페이징 (Paging)
페이징은 프로세스를 동일한 크기의 페이지로 분리하여 메모리에 불연속적으로 저장하는 메모리 관리 방식입니다. 예를 들어, 프로세스가 13MB이고 페이지 크기가 4MB인 경우, 각 페이지는 4MB가 됩니다. 프레임은 일정한 크기(예: 4MB)로 나누어져 메모리에 배치됩니다. 이로 인해 연속 할당 방식보다 내부 단편화가 적게 발생합니다.
세그멘테이션 (Segmentation)
세그멘테이션은 프로세스를 가변적인 크기의 세그먼트로 분리하고 메모리에 적재하는 메모리 관리 방식입니다. 주로 논리적인 블록 단위 세그먼트로 Code, Data, Stack, Heap 등으로 분리할 수 있습니다. 세그멘테이션 역시 외부 단편화가 발생할 수 있습니다.
단편화
내부 단편화는 고정 길이 할당 또는 페이지 기반 할당에서 발생하며, 물리 메모리를 고정된 길이의 파티션 또는 페이지로 분할할 때, 해당 파티션 또는 페이지의 실제 데이터보다 작은 크기의 공간이 남는 현상을 의미합니다.
예를 들어, 물리 메모리를 4KB 페이지로 분할하고 프로세스가 2KB 데이터를 저장한다면, 이 페이지에는 2KB의 내용과 2KB의 빈 공간이 발생하게 됩니다. 이 빈 공간은 사용할 수 없으며 메모리 공간을 낭비하게 됩니다.
외부 단편화는 가변 길이 할당 또는 세그멘테이션에서 주로 발생합니다. 물리 메모리의 최대 크기에서 현재 사용 중인 공간의 크기를 뺀 나머지 공간을 차지하지 못할 만큼 작은 조각으로 나누는 현상을 의미합니다. 이로 인해 새로운 프로세스를 메모리에 적재할 때, 이러한 조각들로 인해 적재할 공간을 찾지 못하게 됩니다.
예를 들어, 메모리에 여러 프로세스가 로드되어 있고 중간에 작은 빈 공간이 여러 개 있다면, 이 작은 빈 공간들이 외부 단편화를 형성하게 됩니다. 크기가 충분하더라도 연속된 공간이 아니므로 새로운 프로세스를 적재할 수 없습니다.
내부 단편화와 외부 단편화는 메모리 관리에서 중요한 문제이며, 효율적인 메모리 할당과 해제 전략을 사용하여 최소화해야 합니다.
페이지 교체 알고리즘 (Page Replacement Algorithms)
운영체제에서 메모리를 관리하는 페이징 기법에서 필요한 페이지가 주기억장치에 적재되지 않았을 때, 어떤 페이지 프레임을 교체할 것인지 결정하는 방법을 페이지 교체 알고리즘이라고 합니다. 다양한 페이지 교체 알고리즘이 존재하며, 이들 중 몇 가지 주요한 알고리즘을 설명하겠습니다.
FIFO 알고리즘은 가장 간단한 알고리즘으로, 메모리에 올라온 지 가장 오래된 페이지를 교체합니다. 이 알고리즘은 큐(Queue) 자료구조를 사용하여 페이지가 메모리에 올라온 순서를 저장하고, 교체가 필요할 때 가장 먼저 들어온 페이지를 교체합니다. 간단하고 초기화 코드에 적절한 방법이지만, 페이지 교체의 효율성이 낮을 수 있습니다.
최적 페이지 교체는 가장 오랫동안 사용되지 않을 페이지를 교체하는 알고리즘입니다. 이 알고리즘은 이론적으로는 가장 효율적인 알고리즘으로 모든 페이지 참조 시퀀스를 미리 파악해야 합니다. 그러나 실제 활용에선 알 방법이 없기 때문에 주로 연구를 위해 사용됩니다.
LRU 알고리즘은 가장 오래 사용되지 않은 페이지를 교체하는 알고리즘입니다. 이전에 참조된 페이지 중에서 오래 전에 참조된 페이지를 교체합니다. OPT 알고리즘의 방식과 유사한 효과를 낼 수 있으며, FIFO 알고리즘보다 효율적입니다.
LFU 알고리즘은 참조 횟수가 가장 작은 페이지를 교체하는 알고리즘입니다. 대상인 페이지가 여러 개일 경우, LRU 알고리즘을 따라 가장 오래 사용되지 않은 페이지로 교체합니다. LFU와 MFU 알고리즘은 실제 사용에 잘 쓰이지 않는데, 이유는 구현에 상당한 비용이 들고, 최적 페이지 교체 정책을 제대로 유사하게 구현하기 어렵기 때문입니다.
Thrashing(쓰레싱)란?
Thrashing(쓰레싱)은 페이지 부재율이 높은 상태를 의미합니다. 이 상태에서는 메모리 부재로 인해 프로세스가 원활하게 실행되지 못하며, 다음과 같은 상황에서 발생합니다.
메모리 부재: 페이지 부재가 발생하면 페이지 교체나 페이지 로드가 필요합니다. 여러 프로세스가 메모리에 올라옴에 따라 메모리의 유효 사용 가능한 공간이 줄어들고, CPU 사용 시간이 증가하면서 자원을 최대한 활용하게 됩니다.
메모리 과다 사용: 그러나 메모리에 너무 많은 프로세스가 올라가면, 프로세스당 사용 가능한 물리 메모리 프레임의 수가 감소하며, 페이지가 물리 메모리에 부족하게 올라가는 경우가 발생합니다. 이로 인해 페이지 교체와 Page Fault가 빈번하게 발생하며 CPU 사용률이 감소합니다.
CPU 놀림 현상: 페이지를 교체하는 과정에서 CPU가 사용되지 않고 페이지 교체만 지속적으로 실행됩니다. 이때 운영체제는 CPU가 놀고 있으므로 더 많은 프로세스를 메모리에 올리려고 시도하면서 악순환이 발생합니다. 이 현상을 Thrashing(쓰레싱)이라고 부릅니다.
Thrashing을 해결하기 위해서는 다음과 같은 알고리즘을 사용합니다:
Working Set(워킹 셋) 알고리즘: 대부분의 프로세스가 특정 페이지를 집중적으로 참조하는 특성을 이용하여, 참조되는 페이지의 개수를 파악하고 그 페이지 수만큼 여분의 프레임을 확보하는 알고리즘입니다.
Page Fault Frequency(페이지 폴트 빈도) 알고리즘: 페이지 폴트 비율의 상한과 하한을 설정하여 상한을 넘으면 페이지에게 지급하는 프레임 개수를 늘리고, 하한을 넘으면 지급 프레임 개수를 줄입니다.
또한, CPU 사용률과 메모리 적재량을 함께 체크하여 쓰레싱 상태를 확인하고 관리합니다.
메모리 할당 방식
연속 할당 방식은 프로세스 이미지가 분리되지 않은 온전한 프로세스를 메인 메모리에 적재하는 방식입니다. 이 방식에는 크게 두 가지 하위 방식이 있습니다.
메모리를 고정된 길이로 파트로 분리하고, 프로세스를 해당 파트에 삽입합니다. 각 파트는 고정된 크기를 가지므로 내부 단편화가 발생할 수 있습니다. 내부 단편화란 파트 내에 프로세스가 들어가면서 생기는 여백을 의미합니다.
메모리를 프로세스의 길이에 따라 동적으로 파트로 분리하고, 해당 프로세스를 적재합니다. 가변 길이 할당을 사용하면 내부 단편화는 발생하지 않지만, 파트의 크기가 가변하기 때문에 외부 단편화가 발생할 수 있습니다. 외부 단편화는 파트 간의 빈 공간을 의미합니다.
불연속 할당 방식은 프로세스가 연속된 이미지가 아닌 분리된 이미지로 구성되어 메인 메모리에 적재하는 방식입니다. 이 방식에는 두 가지 주요 방식이 있습니다.
프로세스를 동일한 크기의 페이지로 분리하고, 메모리는 해당 페이지와 동일한 크기의 프레임으로 분리하여 불연속적으로 저장합니다. 예를 들어, 프로세스가 13MB이고 페이지 크기가 4MB라면, 한 페이지는 4MB가 됩니다. 이 방식에서는 프레임 크기가 고정되어 있으므로 내부 단편화가 발생할 수 있습니다.
프로세스를 가변적인 크기의 세그먼트로 분리하고 메모리에 적재합니다. 주로 논리적 블록 단위로 세그먼트를 분리할 수 있으며, 예를 들어 Code, Data, Stack, Heap 등으로 분리할 수 있습니다. 세그멘테이션 역시 외부 단편화가 발생할 수 있습니다. 외부 단편화는 세그먼트 간의 빈 공간을 의미합니다.