STUDY/정글

[Jungle] w11 Quiz

Nobb 2025. 11. 25. 14:25

 

Q1. 커널모드에서 실행될수있는 작업의 예를들고 이러한

작업들이 사용자 모드에서 실행되지 않는 이유가 뭐야?

 

  • 하드웨어 직접 접근 및 제어:
    • 입/출력(I/O) 작업: 디스크 드라이브, 네트워크 카드, 프린터 등의 물리적인 장치 드라이버를 통해 하드웨어 레지스터에 직접 접근하여 데이터를 읽거나 쓰는 작업.
    • 인터럽트(Interrupt) 처리: 하드웨어 장치나 예외 상황 발생 시 CPU 제어권을 넘겨받아 해당 이벤트를 처리하는 작업.
  • 메모리 관리:
    • 가상 메모리 관리: 프로세스에 메모리를 할당하거나 해제하고, 물리적 메모리와 가상 메모리 주소 간의 **매핑(Mapping)**을 설정하는 작업.
    • 페이지 폴트(Page Fault) 처리: 프로세스가 접근하려는 메모리 페이지가 물리적 메모리에 없을 때 이를 처리하고 디스크에서 로드하는 작업.
  • 프로세스 및 스레드 관리:
    • 문맥 교환(Context Switching): 현재 실행 중인 프로세스의 상태를 저장하고 다른 프로세스의 상태를 불러와 CPU를 전환하는 작업.
    • 스케줄링: 다음에 실행될 프로세스나 스레드를 결정하는 작업.

사용자 모드에서 실행되지 않는 이유 (보호 메커니즘)

이러한 중요하고 민감한 작업들이 **사용자 모드(User Mode)**에서 실행되지 않고 커널 모드에서만 실행되도록 하는 것은 운영체제가 시스템의 안정성과 보안을 유지하기 위한 핵심적인 보호 메커니즘입니다.

  1. 시스템 안정성 보호:
    • 사용자 모드 프로그램은 버그나 오류가 발생하기 쉽습니다. 만약 사용자 프로그램이 하드웨어에 직접 접근하거나 중요한 메모리 영역을 수정할 수 있다면, 하나의 오류가 전체 시스템을 충돌(Crash)시키거나 손상시킬 수 있습니다.
    • 커널 모드 접근을 제한함으로써, 문제 있는 사용자 프로그램은 자신의 메모리 공간 내에서만 영향을 미치도록 분리됩니다.
  2. 자원 접근 제어 및 보안:
    • 모든 프로그램이 하드웨어 자원(예: 디스크, 네트워크)에 무분별하게 접근하는 것을 막고, 오직 **운영체제(커널)**만이 이러한 접근을 통제하고 승인할 수 있도록 합니다.
    • 이는 악의적인 프로그램이 다른 프로세스의 데이터나 시스템 파일을 훼손하거나 훔치는 것을 방지하는 기본적인 보안 조치입니다.
  3. 다중 프로그래밍 환경 지원:
    • 여러 개의 프로세스가 동시에 실행되는 환경에서, 커널은 자원을 공유하고 배분하는 유일한 중재자 역할을 수행합니다.
    • 커널 모드를 통해서만 자원을 관리함으로써, 각 프로세스가 공평하고 안전하게 시스템 자원을 사용할 수 있도록 보장합니다.

사용자 모드 프로그램이 커널 모드의 기능이 필요할 때는, 직접 접근하는 대신 **시스템 호출(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), 또는 특정 패턴을 사용하는 것이 더 안전하고 권장되는 방식입니다.