[Jungle] w11 Quiz

Q1. 커널모드에서 실행될수있는 작업의 예를들고 이러한
작업들이 사용자 모드에서 실행되지 않는 이유가 뭐야?
- 하드웨어 직접 접근 및 제어:
- 입/출력(I/O) 작업: 디스크 드라이브, 네트워크 카드, 프린터 등의 물리적인 장치 드라이버를 통해 하드웨어 레지스터에 직접 접근하여 데이터를 읽거나 쓰는 작업.
- 인터럽트(Interrupt) 처리: 하드웨어 장치나 예외 상황 발생 시 CPU 제어권을 넘겨받아 해당 이벤트를 처리하는 작업.
- 메모리 관리:
- 가상 메모리 관리: 프로세스에 메모리를 할당하거나 해제하고, 물리적 메모리와 가상 메모리 주소 간의 **매핑(Mapping)**을 설정하는 작업.
- 페이지 폴트(Page Fault) 처리: 프로세스가 접근하려는 메모리 페이지가 물리적 메모리에 없을 때 이를 처리하고 디스크에서 로드하는 작업.
- 프로세스 및 스레드 관리:
- 문맥 교환(Context Switching): 현재 실행 중인 프로세스의 상태를 저장하고 다른 프로세스의 상태를 불러와 CPU를 전환하는 작업.
- 스케줄링: 다음에 실행될 프로세스나 스레드를 결정하는 작업.
사용자 모드에서 실행되지 않는 이유 (보호 메커니즘)
이러한 중요하고 민감한 작업들이 **사용자 모드(User Mode)**에서 실행되지 않고 커널 모드에서만 실행되도록 하는 것은 운영체제가 시스템의 안정성과 보안을 유지하기 위한 핵심적인 보호 메커니즘입니다.
- 시스템 안정성 보호:
- 사용자 모드 프로그램은 버그나 오류가 발생하기 쉽습니다. 만약 사용자 프로그램이 하드웨어에 직접 접근하거나 중요한 메모리 영역을 수정할 수 있다면, 하나의 오류가 전체 시스템을 충돌(Crash)시키거나 손상시킬 수 있습니다.
- 커널 모드 접근을 제한함으로써, 문제 있는 사용자 프로그램은 자신의 메모리 공간 내에서만 영향을 미치도록 분리됩니다.
- 자원 접근 제어 및 보안:
- 모든 프로그램이 하드웨어 자원(예: 디스크, 네트워크)에 무분별하게 접근하는 것을 막고, 오직 **운영체제(커널)**만이 이러한 접근을 통제하고 승인할 수 있도록 합니다.
- 이는 악의적인 프로그램이 다른 프로세스의 데이터나 시스템 파일을 훼손하거나 훔치는 것을 방지하는 기본적인 보안 조치입니다.
- 다중 프로그래밍 환경 지원:
- 여러 개의 프로세스가 동시에 실행되는 환경에서, 커널은 자원을 공유하고 배분하는 유일한 중재자 역할을 수행합니다.
- 커널 모드를 통해서만 자원을 관리함으로써, 각 프로세스가 공평하고 안전하게 시스템 자원을 사용할 수 있도록 보장합니다.
사용자 모드 프로그램이 커널 모드의 기능이 필요할 때는, 직접 접근하는 대신 **시스템 호출(System Call)**이라는 메커니즘을 통해 커널에게 작업을 요청하며, 커널은 이 요청을 안전하게 검증하고 수행합니다.
Q2. MLFQS 사용하는 가장 큰 이유가 뭐야?
1. MLFQS의 핵심 개념 (Multi-Level + Feedback)
MLFQS는 이름에서 알 수 있듯이, 여러 개의 준비 큐(Ready Queue)와 프로세스의 행동에 따른 피드백 메커니즘을 결합한 스케줄링 기법입니다.
A. Multi-Level (다단계 큐)
- 여러 개의 큐: 시스템에는 여러 개의 준비 큐($Q_0, Q_1, Q_2, \dots$)가 존재하며, 각 큐는 서로 다른 우선순위와 시간 할당량(Time Quantum)을 가집니다.
- 우선순위: 상위 큐일수록 우선순위가 높습니다. 스케줄러는 항상 가장 높은 우선순위의 큐에서 실행할 프로세스를 선택합니다. (상위 큐가 비어 있어야만 하위 큐의 프로세스가 실행될 수 있습니다.)
- 시간 할당량: 일반적으로 높은 우선순위 큐일수록 시간 할당량이 짧습니다.
B. Feedback (피드백 메커니즘)
프로세스는 큐 간에 이동할 수 있으며, 이 이동은 프로세스가 CPU를 사용하는 방식(행동)에 따라 결정됩니다.
| 규칙 | 동작 | 효과 |
| 강등 (Demotion) | 프로세스가 현재 큐에서 주어진 시간 할당량을 모두 사용하면, 다음 하위 큐로 이동하여 우선순위가 낮아집니다. | CPU를 집중적으로 오래 사용하는 작업(CPU-bound)의 우선순위를 낮춥니다. |
| 유지 (Maintenance) | 프로세스가 주어진 시간 할당량을 다 사용하기 전에 입출력(I/O) 등의 이유로 CPU를 자발적으로 반납하면, 현재 큐의 우선순위를 유지합니다. | 입출력 위주의 작업(I/O-bound, 대화형 작업)의 우선순위를 높게 유지하여 빠른 응답 시간을 보장합니다. |
Q3. fork로 생성할 때와 exec으로 생성할 때의 차이는?
- fork(): **현재 실행 중인 프로세스의 복사본(자식 프로세스)**을 만듭니다. (동일한 프로그램 코드 실행)
- exec(): **현재 프로세스를 완전히 새로운 프로그램으로 교체(덮어쓰기)**합니다. (다른 프로그램 코드 실행)
Q4. 유저프로그램에서 스택은 높->낮 주소, 힙은 낮->높 주소로 성장하도록 설계되어있음. 이렇게 반대방향으로 설계된 이유를 운영체제 관점에서 설명하라.
📈 사용자 프로그램 메모리 구조: 스택과 힙이 반대 방향으로 성장하는 이유
사용자 프로그램의 메모리 공간에서 **스택(Stack)**은 높은 주소 $\rightarrow$ 낮은 주소 방향으로, **힙(Heap)**은 낮은 주소 $\rightarrow$ 높은 주소 방향으로 성장하도록 설계된 가장 큰 이유는 두 영역 사이에 최대한의 유연성을 제공하여 메모리 낭비를 줄이고 효율적인 관리를 가능하게 하기 위함입니다. 이는 주로 **운영체제(OS)**와 컴파일러의 설계 철학을 반영합니다.
1. 설계의 기본 원칙: 메모리 공간의 효율적 활용
운영체제는 프로세스에게 할당된 가상 주소 공간 내에서 스택과 힙을 서로 가장 먼 곳에 배치합니다.
- 스택 (높은 주소 시작): 함수 호출, 지역 변수 등 예측 가능한 메모리 사용을 처리합니다.
- 힙 (낮은 주소 시작): malloc, new와 같은 동적 할당에 사용되며, 예측 불가능한 메모리 사용을 처리합니다.
두 영역이 반대 방향으로 성장하면, 메모리 주소 공간의 중앙에 **사용되지 않는 공간(Free Space)**을 확보하게 됩니다.
이 중앙의 빈 공간은 스택과 힙이 서로 침범하지 않으면서 필요에 따라 최대한 확장할 수 있는 버퍼 역할을 합니다. 프로세스가 실행되는 동안 스택이 깊어지거나 힙 할당이 많아져도, 메모리 공간이 허용하는 한 유연하게 성장할 수 있습니다.
2. 운영체제 관점의 관리 용이성
이러한 설계는 운영체제가 프로세스의 메모리를 관리하는 데 다음과 같은 이점을 제공합니다.
- 충돌 감지 (Collision Detection):
- 스택과 힙이 서로를 향해 성장하다가 만나게 되면 이를 메모리 오버플로우(Memory Overflow) 또는 경계 침범으로 간주할 수 있습니다.
- 운영체제는 이 지점을 최대 메모리 사용량으로 판단하고 프로세스를 종료시키거나 메모리 할당 실패를 반환함으로써 시스템 안정성을 유지합니다.
- 스케일링의 유연성:
- 운영체제는 프로세스의 초기 실행 시점에 스택과 힙의 크기를 미리 고정할 필요가 없습니다.
- 힙이 더 필요하면 페이지(Page) 단위로 힙 영역을 확장하고, 스택이 더 필요하면 스택 영역을 확장할 수 있습니다. (이는 가상 메모리 시스템과 연계되어 메모리 맵을 효율적으로 관리하게 합니다.)
만약 스택과 힙이 같은 방향(예: 둘 다 낮은 주소 $\rightarrow$ 높은 주소)으로 성장하도록 설계된다면, 운영체제는 둘 중 하나의 영역에 최대 크기를 미리 지정해야 하며, 이는 다른 영역의 잠재적인 성장을 불필요하게 제한하여 메모리 낭비를 초래하게 됩니다.
Q5. ifdef 함수의 장단점은?
#ifdef는 "If Defined"의 줄임말로, 특정 매크로가 정의되어 있는지에 따라 컴파일할 코드 블록을 결정하는 데 사용됩니다.
주된 이점은 코드의 유연성, 이식성, 그리고 디버깅 용이성을 높이는 데 있습니다.
#ifdef의 과도한 사용은 코드를 복잡하게 만들고 유지보수를 어렵게 할 수 있습니다.
현대 C++에서는 복잡한 조건부 로직을 처리할 때 템플릿(Templates), 다형성(Polymorphism), 또는 특정 패턴을 사용하는 것이 더 안전하고 권장되는 방식입니다.