Notice
Recent Posts
Recent Comments
Link
| 일 | 월 | 화 | 수 | 목 | 금 | 토 |
|---|---|---|---|---|---|---|
| 1 | ||||||
| 2 | 3 | 4 | 5 | 6 | 7 | 8 |
| 9 | 10 | 11 | 12 | 13 | 14 | 15 |
| 16 | 17 | 18 | 19 | 20 | 21 | 22 |
| 23 | 24 | 25 | 26 | 27 | 28 | 29 |
| 30 | 31 |
Tags
- ndc2025
- 서버 개발자
- 자바 #자바문법 #자바기초 #참조형 #기본형
- 이분탐색
- 넥슨개발자컨퍼런스
- server engineer
- aws SAA-c03
- 서버 엔지니어
- 반복문
- AWS
- Spring
- tmax tibero
- 2026 하반기 대기업 반드시 갑니다
- Next.js
- static #자바 메모리 구조 #멤버 변수
- tibero 7.23
- software enginner
- java #예외처리 #throw #throws
- java #추상클래스
- level2
- 백엔드 개발자 로드맵
- server developer
- 나는야 4학년 #5학년 까지 가보자구
- heap area #stack area #static area #jvm
- level3
- 정보처리기사 실기 #정처기 실기 #2024년 2회 #정처기 2024년 2회 #공부법 # 꿀팁
- 주니어 백엔드 개발자
- object 클래스 # java
- 25304번
- 올 겨울은 조금 따뜻할 것 같다.
Archives
- Today
- Total
개발자 쿠키
[OS] 운영체제 총정리 본문
기술면접 대비 운영체제 총정리
목차
1. 운영체제와 커널
2. 컴퓨터 시스템 구조 (인터럽트, 시스템 콜)
3. 프로세스와 스레드
4. CPU 스케줄링
5. 프로세스 동기화
6. 데드락
7. 메모리 관리와 가상 메모리
8. 파일 시스템과 디스크
9. 부록 : 리눅스, 문자 인코딩
10. 면접 예상 질문 40선
2. 컴퓨터 시스템 구조 (인터럽트, 시스템 콜)
3. 프로세스와 스레드
4. CPU 스케줄링
5. 프로세스 동기화
6. 데드락
7. 메모리 관리와 가상 메모리
8. 파일 시스템과 디스크
9. 부록 : 리눅스, 문자 인코딩
10. 면접 예상 질문 40선
1. 운영체제와 커널
운영체제: 하드웨어 바로 위에 올라가서사용자, 응용 프로그램과 하드웨어를 연결해주는 소프트웨어 계층
목적: 사용자가 컴퓨터를 편리하게 쓸 수 있는 환경을 제공하고 CPU, 메모리, 디스크 같은 자원을 효율적으로 관리
목적: 사용자가 컴퓨터를 편리하게 쓸 수 있는 환경을 제공하고 CPU, 메모리, 디스크 같은 자원을 효율적으로 관리
커널(Kernel)
부팅 후 메모리에 상주하면서 실제 일을 하는 운영체제의 핵심부. 프로세스 관리, 메모리 관리, 파일 시스템 관리, 입출력 관리를 담당. 응용 프로그램은 커널 기능을 직접 건드릴 수 없고 시스템 콜이라는 인터페이스를 통해서만 요청할 수 있습니다.
셸(Shell)
사용자와 커널 사이의 명령어 해석기. 사용자가 입력한 명령을 해석해서 커널에 전달
bash가 대표적이며, 셸은 커널이 아니라 응용 프로그램
bash가 대표적이며, 셸은 커널이 아니라 응용 프로그램
사용자 모드와 커널 모드
CPU는 모드 비트로 두 가지 모드를 구분
1. 사용자 모드(1): 일반 응용 프로그램이 동작
2. 커널 모드(0): 하드웨어를 직접 제어하는 특권 명령을 수행
잘못 만들어진 프로그램 하나가 시스템 전체를 망가뜨리지 못하게 막는 보호 장치입니다. 인터럽트나 예외가 발생하면 하드웨어가 모드 비트를 0으로 바꾸고, 다시 사용자 프로그램에 CPU를 넘기기 전에 1로 되돌립니다.
1. 사용자 모드(1): 일반 응용 프로그램이 동작
2. 커널 모드(0): 하드웨어를 직접 제어하는 특권 명령을 수행
잘못 만들어진 프로그램 하나가 시스템 전체를 망가뜨리지 못하게 막는 보호 장치입니다. 인터럽트나 예외가 발생하면 하드웨어가 모드 비트를 0으로 바꾸고, 다시 사용자 프로그램에 CPU를 넘기기 전에 1로 되돌립니다.
2. 컴퓨터 시스템 구조 (인터럽트, 시스템 콜)
인터럽트(Interrupt)
CPU가 작업을 수행하는 도중 처리해야 할 사건이 생겼을 때, 현재 작업을 중단하고 그 사건을 먼저 처리하도록 알리는 신호입니다. 폴링(Polling)처럼 CPU가 계속 상태를 확인하지 않아도 되기 때문에 CPU 자원을 낭비하지 않는 것이 핵심 이점
| 구분 | 종류 | 설명 |
|---|---|---|
| 하드웨어 인터럽트 | I/O 완료, 타이머 | 장치 컨트롤러가 CPU에 보내는 비동기 신호 |
| 소프트웨어 인터럽트(Trap) | 예외(Exception) | 0으로 나누기, 잘못된 메모리 접근 등 프로그램 오류 |
| 소프트웨어 인터럽트(Trap) | 시스템 콜 | 프로그램이 의도적으로 커널 기능을 호출 |
동작 순서
이벤트 발생 → CPU가 인터럽트 라인 확인 → 현재 문맥(레지스터,PC)을 PCB에 저장 → 인터럽트 벡터 테이블에서 처리 루틴 주소 조회 → ISR(인터럽트 서비스 루틴) 실행 → 저장한 문맥 복원 후 원래 작업 재개
이벤트 발생 → CPU가 인터럽트 라인 확인 → 현재 문맥(레지스터,PC)을 PCB에 저장 → 인터럽트 벡터 테이블에서 처리 루틴 주소 조회 → ISR(인터럽트 서비스 루틴) 실행 → 저장한 문맥 복원 후 원래 작업 재개
시스템 콜 (System Call)
사용자 프로그램이 커널의 서비스를 받기 위해 커널 함수를 호출하는 것입니다. 시스템 콜이 호출되면 트랩이 발생하고 모드가 커널 모드로 전환됩니다.
☕ 자바와의 연결
자바에서
자바에서
new FileInputStream()으로 파일을 읽는 것도 결국 JNI를 통해 커널의 read() 시스템 콜로 내려갑니다. I/O가 느린 이유가 단순히 디스크 때문만이 아니라 사용자 모드 ↔ 커널 모드 전환 비용도 포함된다는 걸 알면, NIO의 다이렉트 버퍼나 제로 카피(zero-copy)가 왜 나왔는지 설명할 수 있습니다.동기식, 비동기식 입출력과 DMA
동기식 I/O : 입출력이 끝나야 제어가 프로그램에 돌아옵니다. 이때 CPU를 놀리는 대신, 해당 프로세스를 대기(Waiting) 상태로 보내고 다른 프로세스에 CPU를 줍니다.
비동기식 I/O : 입출력 요청 후 완료를 기다리지 않고 바로 제어가 넘어옵니다.
DMA : CPU의 중재 없이 장치 컨트롤러가 메모리에 직접 데이터를 전송합니다. 바이트마다 인터럽트를 걸지 않고 블록 단위로 걸기 때문에 인터럽트 부담이 크게 줄어듭니다.
비동기식 I/O : 입출력 요청 후 완료를 기다리지 않고 바로 제어가 넘어옵니다.
DMA : CPU의 중재 없이 장치 컨트롤러가 메모리에 직접 데이터를 전송합니다. 바이트마다 인터럽트를 걸지 않고 블록 단위로 걸기 때문에 인터럽트 부담이 크게 줄어듭니다.
동기/비동기 vs 블로킹/논블로킹
동기/비동기: 작업의 결과와 순서에 관심이 있는가의 문제
블로킹/논블로킹: 제어권을 넘기고 기다리는가의 문제
그래서 네 가지 조합이 모두 존재합니다.
스프링 MVC는 Sync-Blocking, WebFlux는 Async-Non-Blocking에 가깝습니다.
블로킹/논블로킹: 제어권을 넘기고 기다리는가의 문제
그래서 네 가지 조합이 모두 존재합니다.
스프링 MVC는 Sync-Blocking, WebFlux는 Async-Non-Blocking에 가깝습니다.
3. 프로세스와 스레드
프로세스는 메모리에 올라가서 실행 중인 프로그램이고, 스레드는 그 프로세스 안에서 실행되는 흐름의 단위입니다.
가장 중요한 차이는 메모리를 공유하느냐 입니다.
가장 중요한 차이는 메모리를 공유하느냐 입니다.
프로세스 주소 공간
| 영역 | 저장되는 것 | 스레드 간 공유 |
|---|---|---|
| 코드(Text) | 기계어로 변환된 프로그램 코드 | 공유 |
| 데이터(Data) | 전역 변수, static 변수, 상수 | 공유 |
| 힙(Heap) | 동적으로 할당된 객체 (런타임에 크기 결정) | 공유 |
| 스택(Stack) | 지역 변수, 매개변수, 함수 복귀 주소 | 스레드마다 별도 |
PCB와 Context Switching
PCB(Process Control Block)는 운영체제가 프로세스를 관리하기 위해 프로세스마다 유지하는 자료구조입니다. 프로세스 ID, 상태, 프로그램 카운터, 레지스터 값, 메모리 정보, 열린 파일 목록 등이 담깁니다.
Context Switching은 CPU가 한 프로세스에서 다른 프로세스로 전환할 때, 기존 프로세스의 상태를 PCB에 저장하고 새 프로세스의 상태를 PCB에서 복원하는 과정입니다. 수행 주체는 Dispatcher이고 전환할 프로세스를 고르는 것은 스케줄러입니다.
왜 비용이 큰가? 레지스터 저장, 복원 자체보다 프로세스가 바뀌면 캐시와 TLB가 무효화되어 새 프로세스가 다시 캐시를 채우는 동안 성능이 떨어지기 때문입니다. 스레드 간 전환은 주소 공간이 같아서 페이지 테이블을 교체할 필요가 없으므로 상대적으로 가볍습니다.
프로세스 상태 전이
생성(New) → 준비(Ready) → 실행(Running) → 종료(Terminated)
실행 중 I/O를 요청하면 대기(Waiting)로 빠졌다가 완료되면 다시 준비 상태로 돌아옵니다.
실행 중 I/O를 요청하면 대기(Waiting)로 빠졌다가 완료되면 다시 준비 상태로 돌아옵니다.
대기 → 실행으로 바로 못 가는 이유: I/O가 끝나도 CPU가 비어 있다는 보장이 없기 때문에 반드시 준비 큐를 거쳐 스케줄러의 선택을 받아야 합니다.
고아 프로세스와 좀비 프로세스
고아 프로세스 : 자식이 아직 실행 중인데 부모가 먼저 종료된 경우. init(PID 1)이 새 부모가 되어 정리해줍니다.
좀비 프로세스 : 자식은 종료됐는데 부모가 wait()로 종료 상태를 수거하지 않아 프로세스 테이블에 남아 있는 경우. PID 자원을 계속 점유하므로 문제가 됩니다.
좀비 프로세스 : 자식은 종료됐는데 부모가 wait()로 종료 상태를 수거하지 않아 프로세스 테이블에 남아 있는 경우. PID 자원을 계속 점유하므로 문제가 됩니다.
IPC (프로세스 간 통신)
프로세스는 각자 독립된 주소 공간을 갖기 때문에 서로의 변수에 직접 접근할 수 없습니다. 그래서 커널이 제공하는 통신 수단이 필요합니다.
| 방식 | 특징 |
|---|---|
| 공유 메모리 | 커널이 할당한 메모리 영역을 여러 프로세스가 붙여서 사용. 커널 개입이 없어 가장 빠르지만 동기화는 직접 처리해야 함 (shmget → shmat → shmdt → shmctl) |
| 파이프 | 단방향 통신. 부모-자식처럼 혈연 관계인 프로세스끼리 사용. 읽기용 fd[0], 쓰기용 fd[1] |
| named pipe | 파일 시스템에 이름을 가진 파이프. 관계 없는 프로세스끼리도 가능 |
| 메시지 큐 | 커널이 관리하는 큐에 메시지 단위로 송수신. 비동기, 다대다 가능 |
| 소켓 | 네트워크를 통해 다른 머신의 프로세스와도 통신 가능. 서버는 socket → bind → listen → accept, 클라이언트는 socket → connect |
| 시그널 | 이벤트 발생을 알리는 비동기 알림 (SIGKILL, SIGTERM 등) |
멀티프로세스 vs 멀티스레드
| 기준 | 멀티프로세스 | 멀티스레드 |
|---|---|---|
| 메모리 | 독립 | 코드, 데이터, 힙 공유 | 스택은 개별 |
| 생성 비용 | 큼 | 작음 |
| 통신 | IPC 필요 | 변수 직접 공유 |
| 안정성 | 하나가 죽어도 나머지는 영향 없음 | 하나가 죽으면 프로세스 전체가 위험 |
| 동기화 | 거의 불필요 | 필수, 설계 난이도 상승 |
☕ 자바와의 연결 : 스레드는 많을수록 좋은가
톰캣의 기본 최대 스레드는 200개입니다. 무작정 늘리면 컨텍스트 스위칭 오버헤드와 스레드당 스택 메모리(기본 1MB) 때문에 오히려 처리량이 떨어집니다. 스레드 수는 CPU 바운드 작업이면 코어 수 근처, I/O 바운드면 그보다 크게 잡는 것이 기본 원칙입니다.
톰캣의 기본 최대 스레드는 200개입니다. 무작정 늘리면 컨텍스트 스위칭 오버헤드와 스레드당 스택 메모리(기본 1MB) 때문에 오히려 처리량이 떨어집니다. 스레드 수는 CPU 바운드 작업이면 코어 수 근처, I/O 바운드면 그보다 크게 잡는 것이 기본 원칙입니다.
4. CPU 스케줄링
CPU 스케줄링은 준비 큐에 있는 프로세스 중 어떤 프로세스에게 CPU를 줄지 결정하는 일입니다. 스케줄링이 없다면 급하지 않은 작업이 CPU를 오래 붙잡고, 정작 실행되어야 할 프로세스가 밀리는 무질서한 상황이 생깁니다.
선점형과 비선점형
선점형 (Preemptive) : 프로세스가 CPU를 쓰고 있어도 운영체제가 강제로 뺏어 다른 프로세스에 줄 수 있습니다. 응답 시간이 짧지만 컨텍스트 스위칭 오버헤드와 경쟁 상태가 발생할 수 있습니다.
비선점형 (Non-preemptive) : 프로세스가 스스로 CPU를 놓기 전까지는 뺏을 수 없습니다. 오버헤드는 적지만 응답 시간이 길어질 수 있습니다.
비선점형 (Non-preemptive) : 프로세스가 스스로 CPU를 놓기 전까지는 뺏을 수 없습니다. 오버헤드는 적지만 응답 시간이 길어질 수 있습니다.
스케줄링 평가 기준
CPU 이용률과 처리량은 높을수록 좋고, 반환 시간, 대기 시간, 응답 시간은 낮을수록 좋습니다. 응답 시간은 첫 응답까지 걸린 시간이라 대화형 시스템에서 특히 중요합니다.
주요 알고리즘
| 알고리즘 | 방식 | 문제점 |
|---|---|---|
| FCFS (비선점) | 준비 큐에 들어온 순서대로 처리 | 호위 효과(Convoy Effect): 긴 작업 뒤의 짧은 작업이 오래 대기 |
| SJF (비선점) | 실행 시간이 가장 짧은 프로세스 먼저 | 긴 작업의 기아(Starvation), 실행 시간을 미리 알 수 없음 |
| SRT (선점) | 남은 실행 시간이 더 짧은 작업이 오면 교체 | 기아 + 잦은 컨텍스트 스위칭 |
| RR (선점) | 타임 슬라이스만큼 돌아가며 사용 | 슬라이스가 크면 FCFS처럼, 작으면 스위칭 비용 폭증 |
| 우선순위 | 우선순위가 높은 프로세스 먼저 | 기아 → 에이징(Aging)으로 해결 |
| 다단계 큐 | 우선순위별로 큐를 여러 개 운영, 큐마다 다른 알고리즘 적용 가능 | 큐 간 이동 불가 → 낮은 큐의 기아 |
| 다단계 피드백 큐 | 큐 사이를 이동 가능. CPU를 오래 쓰면 낮은 우선순위 큐로 강등, 오래 기다리면 승격 | 가장 범용적이지만 구현이 복잡 |
현대 운영체제는 대부분 다단계 피드백 큐를 기반으로 합니다. I/O 바운드 작업은 CPU를 조금 쓰고 금방 반납하므로 우선순위가 유지되고, CPU 바운드 작업은 아래 큐로 내려가면서 자연스럽게 응답성과 처리량이 균형을 이룹니다.
5. 프로세스 동기화
경쟁 상태와 임계 구역
Race Condition은 둘 이상의 실행 흐름이 공유 자원에 동시에 접근할 때, 실행 순서에 따라 결과가 달라지는 상황입니다.
count++ 한 줄도 기계어에서는 읽기 → 증가 → 쓰기 세 단계라서, 중간에 컨텍스트 스위칭이 일어나면 값이 유실됩니다. 이렇게 공유 자원에 접근하는 코드 구간을 임계 구역(Critical Section)이라고 합니다.임계 구역 해결의 세 가지 조건
상호 배제 : 한 프로세스가 임계 구역에 있으면 다른 프로세스는 진입할 수 없다
진행(Progress) : 임계 구역이 비어 있다면 진입하려는 프로세스는 들어갈 수 있어야 한다
한정 대기(Bounded Waiting) : 대기 시간이 무한하면 안 된다 (기아 방지)
상호 배제 : 한 프로세스가 임계 구역에 있으면 다른 프로세스는 진입할 수 없다
진행(Progress) : 임계 구역이 비어 있다면 진입하려는 프로세스는 들어갈 수 있어야 한다
한정 대기(Bounded Waiting) : 대기 시간이 무한하면 안 된다 (기아 방지)
뮤텍스, 세마포어, 모니터
| 기법 | 핵심 | 자바 대응 |
|---|---|---|
| 뮤텍스 | lock / unlock. 한 번에 하나만 진입. 락을 건 주체만 풀 수 있음(소유권 존재) | ReentrantLock |
| 세마포어 | P(wait) / V(signal) 연산과 카운터. N개까지 동시 접근 허용. 소유권 없음 | java.util.concurrent.Semaphore |
| 모니터 | 공유 자원과 접근 함수를 객체로 캡슐화해 언어 차원에서 상호 배제를 보장 | synchronized + wait/notify |
☕ 자바와의 연결 : 자바 객체는 모두 모니터를 갖는다
자바의 모든 객체는 모니터 락을 하나씩 가지고 있고,
세마포어는 커넥션 풀을 떠올리면 이해가 쉽습니다. HikariCP에서 최대 커넥션 10개를 설정하는 것은 카운팅 세마포어의 값을 10으로 두는 것과 같습니다. 11번째 요청 스레드는 누군가 커넥션을 반납할 때까지 대기하게 됩니다.
자바의 모든 객체는 모니터 락을 하나씩 가지고 있고,
synchronized는 그 락을 획득, 반납하는 문법입니다. 운영체제의 모니터 개념이 언어 레벨로 내려온 대표적 사례입니다. 세마포어는 커넥션 풀을 떠올리면 이해가 쉽습니다. HikariCP에서 최대 커넥션 10개를 설정하는 것은 카운팅 세마포어의 값을 10으로 두는 것과 같습니다. 11번째 요청 스레드는 누군가 커넥션을 반납할 때까지 대기하게 됩니다.
상호 배제 소프트웨어 알고리즘
데커 알고리즘 : flag(진입 의사)와 turn(차례) 변수로 상호 배제를 구현한 최초의 해법
피터슨 알고리즘 : 데커와 유사하지만 상대에게 먼저 양보하는 방식이라 훨씬 간결함
제과점(Bakery) 알고리즘 : 번호표를 뽑아 가장 작은 번호부터 진입. N개 프로세스로 확장 가능
피터슨 알고리즘 : 데커와 유사하지만 상대에게 먼저 양보하는 방식이라 훨씬 간결함
제과점(Bakery) 알고리즘 : 번호표를 뽑아 가장 작은 번호부터 진입. N개 프로세스로 확장 가능
6. 데드락(Deadlock)
두 개 이상의 프로세스가 서로가 점유한 자원을 무한정 기다리면서 아무도 진행하지 못하는 상태입니다. A는 자원 1을 쥔 채 자원 2를 기다리고, B는 자원 2를 쥔 채 자원 1을 기다리는 상황이 전형적입니다.
발생의 4가지 필요 조건
1. 상호 배제(Mutual Exclusion) : 자원을 한 번에 한 프로세스만 사용
2. 점유와 대기(Hold and Wait) : 자원을 쥔 채로 다른 자원을 기다림
3. 비선점(No Preemption) : 다른 프로세스의 자원을 강제로 뺏을 수 없음
4. 순환 대기(Circular Wait) : 대기 관계가 원형을 이룸
2. 점유와 대기(Hold and Wait) : 자원을 쥔 채로 다른 자원을 기다림
3. 비선점(No Preemption) : 다른 프로세스의 자원을 강제로 뺏을 수 없음
4. 순환 대기(Circular Wait) : 대기 관계가 원형을 이룸
해결 방법
| 방법 | 내용 |
|---|---|
| 예방(Prevention) | 4가지 조건 중 하나를 원천 차단. 자원을 한꺼번에 할당하거나, 자원에 번호를 매겨 오름차순으로만 요청(순환 대기 차단). 자원 활용률이 떨어짐 |
| 회피(Avoidance) | 할당 후에도 안전 상태(Safe State)가 유지될 때만 자원을 내줌. 은행원 알고리즘이 대표적. 최대 요구량을 미리 알아야 함 |
| 탐지 & 회복 | 자원 할당 그래프에서 사이클을 탐지하고, 프로세스를 강제 종료하거나 자원을 선점해 회복 |
| 무시(Ostrich) | 발생 확률이 낮고 처리 비용이 더 크다면 무시. 실제 대부분의 범용 OS가 택하는 방식 |
☕ 자바, DB와의 연결
DB 트랜잭션 데드락 : 트랜잭션 A는 계좌1 → 계좌2 순으로 락을 잡고, B는 계좌2 → 계좌1 순으로 잡으면 데드락
해결책은 모든 트랜잭션이 동일한 순서(예: ID 오름차순)로 락을 획득하도록 강제하는 것으로 순환 대기 조건을 깨는 방식
timeout :
자바에서는
해결책은 모든 트랜잭션이 동일한 순서(예: ID 오름차순)로 락을 획득하도록 강제하는 것으로 순환 대기 조건을 깨는 방식
timeout :
tryLock(timeout)이나 커넥션 타임아웃 설정은 무한 대기를 끊어 회복하는 현실적인 방법자바에서는
jstack으로 스레드 덤프를 떠서 "Found one Java-level deadlock" 메시지로 확인할 수 있습니다.7. 메모리 관리와 가상 메모리
논리 주소와 물리 주소
프로세스는 자기만의 논리 주소(가상 주소)를 사용하고, 실제 메모리 위치인 물리 주소로의 변환은 MMU라는 하드웨어가 담당합니다. 덕분에 모든 프로세스가 0번지부터 시작하는 것처럼 동작할 수 있고, 서로의 메모리를 침범하지 못하게 격리됩니다.
단편화 (Fragmentation)
외부 단편화 : 빈 공간의 총합은 충분한데, 연속된 공간이 없어서 할당하지 못하는 현상. 연속 할당 방식의 문제
내부 단편화 : 할당한 공간이 요청보다 커서 남는 부분이 낭비되는 현상. 고정 크기로 나누는 페이징의 문제
내부 단편화 : 할당한 공간이 요청보다 커서 남는 부분이 낭비되는 현상. 고정 크기로 나누는 페이징의 문제
Paging vs Segmentation
| 구분 | Paging | Segmentation |
|---|---|---|
| 분할 단위 | 고정 크기의 페이지 (물리 쪽은 프레임) | 코드,데이터,스택 등 논리적 단위의 가변 크기 |
| 주소 구성 | 페이지 번호(page number) + 오프셋(offset) | 세그먼트 번호(segment number) + 오프셋(offset) |
| 단편화 | 외부 단편화 없음 / 내부 단편화 발생 | 내부 단편화 없음 / 외부 단편화 발생 |
| 보호, 공유 | 논리적 경계와 무관해 다소 부정확 | 의미 단위라 권한(read/write/execute) 설정이 자연스러움 |
현대 시스템은 두 방식을 결합한 paged segmentation 사용
페이지 테이블과 TLB
페이지 테이블은 페이지 번호를 프레임 번호로 매핑하는 표이며 메모리에 존재합니다. 그래서 주소 변환을 위해 메모리를 한 번, 실제 데이터를 위해 또 한 번 접근하게 되어 메모리 접근이 2배가 되는 문제가 생깁니다.
이를 해결하는 것이 TLB(Translation Lookaside Buffer)로, 최근 사용한 주소 변환 정보를 담는 캐시입니다. TLB에 있으면(TLB Hit) 메모리 접근 한 번으로 끝납니다.
또한 페이지 테이블 자체가 너무 커지는 문제는 계층적(다단계) 페이지 테이블, 역페이지 테이블 등으로 해결합니다.
또한 페이지 테이블 자체가 너무 커지는 문제는 계층적(다단계) 페이지 테이블, 역페이지 테이블 등으로 해결합니다.
가상 메모리와 요구 페이징
가상 메모리는 프로세스 전체를 메모리에 올리지 않고도 실행할 수 있게 하는 기법입니다. 요구 페이징(Demand Paging)은 당장 필요한 페이지만 메모리에 올리고, 나머지는 디스크의 스왑 영역에 두는 방식입니다.
필요한 페이지가 메모리에 없으면 페이지 폴트(Page Fault)가 발생합니다. 이때 트랩이 걸리고, 커널이 디스크에서 해당 페이지를 읽어 빈 프레임에 올린 뒤 중단된 명령을 재실행합니다. 빈 프레임이 없을 때 어떤 페이지를 내보낼지 고르는 것이 페이지 교체 알고리즘입니다.
페이지 교체 알고리즘
| 알고리즘 | 기준 | 비고 |
|---|---|---|
| FIFO | 가장 먼저 들어온 페이지 | 프레임을 늘렸는데 폴트가 늘어나는 벨라디의 역설 발생 |
| OPT | 앞으로 가장 오래 사용되지 않을 페이지 | 이론상 최적이지만 미래를 알 수 없어 구현 불가. 성능 비교 기준용 |
| LRU | 가장 오래 사용되지 않은 페이지 | 가장 널리 쓰임. 참조 시각 기록 비용이 있음 |
| LFU | 참조 횟수가 가장 적은 페이지 | 초기에 많이 참조된 페이지가 계속 남는 문제 |
| Clock(2차 기회) | 참조 비트가 0인 페이지 | LRU를 근사하면서 오버헤드가 작아 실제 OS에서 채택 |
스래싱(Thrashing)
프로세스에 할당된 프레임이 부족해서 페이지 폴트가 계속 발생하고, CPU가 일은 안 하고 페이지 교체만 하는 상태입니다. 멀티프로그래밍 정도를 높이다 보면 어느 지점부터 CPU 이용률이 급락하는데 그 구간이 스래싱입니다.
해결책 : 워킹 셋(Working Set) 모델로 최근 참조한 페이지 집합만큼은 확보해주거나, PFF(Page Fault Frequency)로 폴트 비율을 보며 프레임을 늘리고 줄입니다. 근본적으로는 멀티프로그래밍 정도를 낮춰야 합니다.
☕ 자바, 인프라와의 연결
JVM 힙을 물리 메모리보다 크게 잡으면 GC가 힙 전체를 훑을 때 스왑이 발생해 애플리케이션이 멈춘 것처럼 보입니다. 그래서 서버 환경에서는 스왑을 끄거나 힙 크기를 물리 메모리 안쪽으로 제한합니다.
컨테이너에서 메모리 limit을 넘기면 커널의 OOM Killer가 프로세스를 강제 종료하는데, 애플리케이션 로그에 아무것도 안 남고 컨테이너만 재시작되는 상황이 이 경우입니다.
LRU는 OS만의 개념이 아니라
컨테이너에서 메모리 limit을 넘기면 커널의 OOM Killer가 프로세스를 강제 종료하는데, 애플리케이션 로그에 아무것도 안 남고 컨테이너만 재시작되는 상황이 이 경우입니다.
LRU는 OS만의 개념이 아니라
LinkedHashMap 기반 캐시나 Redis의 maxmemory-policy allkeys-lru에서도 그대로 쓰입니다.8. 파일 시스템과 디스크
파일 시스템은 저장 장치의 데이터를 파일과 디렉터리 단위로 조직하고 관리하는 체계입니다.
파일 할당 방식
연속 할당 : 연속된 블록에 저장. 접근이 빠르지만 외부 단편화와 파일 크기 확장 문제가 있습니다.
연결 할당 : 각 블록이 다음 블록 주소를 가리킵니다. 단편화는 없지만 임의 접근이 불가능합니다.
색인(Index) 할당 : 인덱스 블록에 블록 주소들을 모아둡니다. 임의 접근이 가능하며 유닉스의 inode가 이 방식입니다.
연결 할당 : 각 블록이 다음 블록 주소를 가리킵니다. 단편화는 없지만 임의 접근이 불가능합니다.
색인(Index) 할당 : 인덱스 블록에 블록 주소들을 모아둡니다. 임의 접근이 가능하며 유닉스의 inode가 이 방식입니다.
inode
파일의 메타데이터(권한, 소유자, 크기, 시간 정보, 데이터 블록 위치)를 담는 구조체입니다. 파일 이름은 inode에 없고 디렉터리에 들어 있습니다. 디렉터리는 파일 이름 → inode 번호 매핑 목록을 담은 특별한 파일이며, 이 구조 덕분에 하드 링크로 같은 파일에 여러 이름을 붙일 수 있습니다.
저널링 파일 시스템
변경 사항을 실제로 반영하기 전에 로그에 먼저 기록해두는 방식입니다. 정전이나 비정상 종료가 발생해도 저널을 보고 복구할 수 있어 전체 디스크 검사가 필요 없습니다. ext4, NTFS가 대표적이며, DB의 WAL(Write Ahead Log)과 완전히 같은 아이디어입니다.
디스크 스케줄링
FCFS : 요청 순서대로. 공정하지만 헤드 이동이 비효율적
SSTF : 현재 헤드에서 가장 가까운 요청부터. 기아 발생 가능
SCAN (엘리베이터) : 한쪽 끝까지 갔다가 방향을 바꿔 돌아오며 처리
C-SCAN : 끝까지 간 뒤 처리 없이 처음으로 돌아와 다시 한 방향으로만 처리. 대기 시간이 균등
LOOK / C-LOOK : 요청이 있는 마지막 지점까지만 이동. 불필요한 이동 제거
SSTF : 현재 헤드에서 가장 가까운 요청부터. 기아 발생 가능
SCAN (엘리베이터) : 한쪽 끝까지 갔다가 방향을 바꿔 돌아오며 처리
C-SCAN : 끝까지 간 뒤 처리 없이 처음으로 돌아와 다시 한 방향으로만 처리. 대기 시간이 균등
LOOK / C-LOOK : 요청이 있는 마지막 지점까지만 이동. 불필요한 이동 제거
9. 부록 : 리눅스와 문자 인코딩
리눅스 구조와 특징
응용 프로그램에서 사용자가 명령을 내리면 셸이 해석해 커널에 전달하고, 커널이 하드웨어를 제어합니다. 유닉스 기반이라 안정성과 보안성이 뛰어나며 멀티 유저·멀티 태스킹을 지원합니다. 파일 접근 권한은 읽기,쓰기,실행 세 가지로 관리됩니다.
자주 묻는 디렉터리
/etc 설정 파일 /var 로그처럼 자주 변하는 데이터 /proc 프로세스와 커널 정보 /dev 장치 파일 /tmp 임시 파일 /usr 실행 파일과 라이브러리
/etc 설정 파일 /var 로그처럼 자주 변하는 데이터 /proc 프로세스와 커널 정보 /dev 장치 파일 /tmp 임시 파일 /usr 실행 파일과 라이브러리
표준 입출력과 리다이렉션
파일 디스크립터 0은 표준 입력, 1은 표준 출력, 2는 표준 에러입니다.
command > out.log 2>&1 은 표준 출력과 표준 에러를 한 파일로 모으는 관용구이며, 서버 로그를 다룰 때 반드시 쓰게 됩니다.>는 덮어쓰기, >>는 이어쓰기입니다. 파이프(|)는 앞 명령의 표준 출력을 뒤 명령의 표준 입력으로 연결합니다.UTF-8 vs EUC-KR
| 구분 | EUC-KR | UTF-8 |
|---|---|---|
| 방식 | 완성형 (완성된 글자만 표현) | 유니코드 가변 길이 인코딩 |
| 한글 1자 | 2바이트 | 3바이트 (영문은 1바이트) |
| 범위 | 한글·영문·일부 기호. 외국어 혼용 어려움 | 전 세계 문자 표현 가능 |
한글이 깨지는 문제는 대부분 인코딩 방식의 불일치에서 발생합니다. JVM 기본 인코딩, DB 문자셋(utf8mb4), HTTP 응답 헤더의 charset을 모두 UTF-8로 통일하는 것이 기본입니다. MySQL에서 이모지가 깨진다면 utf8이 아니라 utf8mb4를 써야합니다
10. 면접 예상 질문

핵심 키워드가 들어가게 짧고 간결하게 말한다.
길게 물어 볼땐 프로젝트하면서 CS로 해결한 문제를 언급한다.
프로세스와 스레드
Q1. 프로세스와 스레드의 차이를 설명해주세요. O
프로세스는 실행 중인 프로그램으로 운영체제로부터 독립된 메모리 공간을 할당받고, 스레드는 그 프로세스 안에서 실행되는 흐름의 단위입니다. 스레드는 코드,데이터,힙을 공유하고 스택과 레지스터만 따로 가집니다. 그래서 생성 비용과 컨텍스트 스위칭 비용이 프로세스보다 훨씬 낮은 대신, 공유 자원 때문에 동기화 문제가 발생합니다.
Q2. 스레드가 스택을 따로 갖는 이유는 무엇인가요?
스택에는 함수 호출 정보와 지역 변수, 복귀 주소가 담깁니다. 스레드는 각자 독립적으로 함수를 호출하며 실행되어야 하므로 스택을 공유하면 서로의 호출 흐름을 덮어써서 정상적인 실행 자체가 불가능해집니다.
Q3. 멀티프로세스 대신 멀티스레드를 쓰는 이유는?
생성,전환 비용이 작고, 자원을 공유하므로 IPC 없이 데이터를 주고받을 수 있어 응답성과 처리량이 좋습니다. 다만 하나의 스레드가 비정상 종료되면 프로세스 전체가 영향을 받기 때문에 브라우저처럼 안정성이 중요한 경우에는 탭마다 프로세스를 분리하기도 합니다. 상황에 따른 트레이드오프입니다.
Q4. PCB에는 무엇이 저장되고 왜 필요한가요?
프로세스 ID, 상태, 프로그램 카운터, 레지스터 값, 메모리 정보, 열린 파일 목록 등이 저장됩니다. 컨텍스트 스위칭 시 중단된 지점부터 정확히 이어서 실행하려면 상태를 어딘가에 보관해야 하는데, 그 저장소가 PCB입니다.
Q5. 컨텍스트 스위칭 비용이 큰 이유는 무엇인가요?
레지스터 저장, 복원 자체도 있지만, 더 큰 비용은 캐시와 TLB가 무효화되는 것입니다. 새 프로세스는 캐시를 처음부터 다시 채워야 하므로 한동안 메모리 접근이 느려집니다. 스레드 간 전환은 주소 공간이 같아 페이지 테이블 교체가 없어 상대적으로 가볍습니다.
Q6. 프로세스 상태에서 대기(Waiting) 상태는 왜 실행 상태로 바로 갈 수 없나요?
I/O가 완료되어 실행할 준비가 되었더라도 CPU가 비어 있다는 보장이 없기 때문입니다. 반드시 준비 큐로 이동해 스케줄러의 선택을 받아야 실행 상태가 됩니다.
Q7. 좀비 프로세스와 고아 프로세스의 차이는?
좀비는 자식이 종료됐는데 부모가 wait()으로 종료 상태를 수거하지 않아 테이블에 남아 있는 경우이고, 고아는 부모가 먼저 종료되어 init 프로세스가 새 부모가 되는 경우입니다. 좀비는 PID를 계속 점유하므로 누적되면 문제가 됩니다.
Q8. IPC 방식에는 어떤 것들이 있나요?
공유 메모리, 파이프와 named pipe, 메시지 큐, 소켓, 시그널이 있습니다. 공유 메모리는 커널 개입이 없어 가장 빠르지만 동기화를 직접 해야 하고, 소켓은 느리지만 다른 머신의 프로세스와도 통신할 수 있습니다.
인터럽트와 시스템 콜
Q9. 인터럽트가 필요한 이유는 무엇인가요?
CPU가 주기적으로 장치 상태를 확인하는 폴링 방식은 확인하는 동안 CPU를 낭비합니다. 인터럽트를 쓰면 사건이 발생했을 때만 알림을 받으므로, CPU는 그 시간에 다른 작업을 수행할 수 있습니다.
Q10. 시스템 콜이란 무엇이고 왜 필요한가요?
사용자 프로그램이 커널의 기능을 사용하기 위한 인터페이스입니다. 응용 프로그램이 하드웨어를 직접 제어하면 시스템 전체가 위험해지므로, 커널 모드로 전환하는 통제된 창구를 두는 것입니다.
Q11. 사용자 모드와 커널 모드를 나눈 이유는?
잘못 작성되거나 악의적인 프로그램이 다른 프로그램이나 운영체제 영역을 침범하지 못하게 하기 위해서입니다. 특권 명령은 커널 모드에서만 수행할 수 있고, 모드 비트로 하드웨어 차원에서 강제됩니다.
Q12. 동기/비동기와 블로킹/논블로킹의 차이는?
동기, 비동기는 작업의 완료 순서와 결과 처리에 관심이 있는지의 문제이고, 블로킹, 논블로킹은 제어권을 넘기고 기다리는지의 문제입니다. 관점이 다르기 때문에 네 가지 조합이 모두 존재합니다.
Q13. DMA는 무엇인가요? (Direct Memory Access)
CPU를 거치지 않고 장치 컨트롤러가 메모리에 직접 데이터를 전송하는 방식입니다. 바이트 단위가 아니라 블록 단위로 인터럽트를 발생시키므로 CPU 부담이 크게 줄어듭니다.
CPU 스케줄링
Q14. 선점형과 비선점형 스케줄링의 차이와 장단점은?
선점형은 OS가 CPU를 강제로 회수할 수 있어 응답성이 좋고 특정 프로세스의 독점을 막지만, 컨텍스트 스위칭 오버헤드와 공유 자원 경쟁 문제가 생깁니다. 비선점형은 오버헤드가 적지만 긴 작업이 CPU를 잡으면 전체 응답 시간이 나빠집니다.
Q15. 기아 현상은 무엇이고 어떻게 해결하나요?
우선순위가 낮은 프로세스가 계속 밀려 무한정 자원을 받지 못하는 상황입니다. 대기 시간이 길어질수록 우선순위를 높여주는 에이징(Aging)으로 해결합니다.
Q16. 라운드 로빈의 타임 슬라이스는 어떻게 정해야 하나요?
너무 크면 FCFS와 다를 바 없어져 호위 효과가 생기고, 너무 작으면 컨텍스트 스위칭 비용이 실제 작업 시간을 압도합니다. 문맥 교환 비용 대비 충분히 크면서 응답 시간을 만족하는 수준에서 결정해야 합니다.
Q17. SJF가 이론적으로 최적인데도 실제로 쓰기 어려운 이유는?
프로세스의 실행 시간을 미리 알 수 없기 때문입니다. 그래서 과거 실행 이력을 지수 평균으로 예측하는 방식을 쓰거나, 다단계 피드백 큐처럼 행동을 보고 사후에 분류하는 방식을 사용합니다.
동기화와 데드락
Q18. 경쟁 상태(Race Condition)란 무엇인가요?
여러 실행 흐름이 공유 자원에 동시에 접근할 때 실행 순서에 따라 결과가 달라지는 상황입니다.
count++처럼 한 줄로 보이는 연산도 읽기,증가,쓰기 세 단계라서 중간에 끼어들면 갱신이 유실됩니다.Q19. 임계 구역 문제 해결의 세 가지 조건은?
상호 배제, 진행, 한정 대기입니다. 상호 배제만 만족하고 한정 대기를 만족하지 못하면 기아가 발생할 수 있다는 점이 포인트입니다.
Q20. 뮤텍스와 세마포어의 차이는?
뮤텍스는 동시에 하나만 접근을 허용하고 락을 획득한 주체만 해제할 수 있어 소유권이 있습니다. 세마포어는 카운터를 두어 N개까지 동시 접근을 허용하고 소유권이 없어 다른 스레드가 signal을 보낼 수도 있습니다. 바이너리 세마포어는 뮤텍스와 비슷하게 동작하지만 소유권 여부에서 차이가 납니다.
Q21. 모니터는 무엇이고 자바에서는 어떻게 구현되어 있나요?
공유 자원과 그 자원에 접근하는 연산을 하나의 객체로 캡슐화해 언어 차원에서 상호 배제를 보장하는 기법입니다. 자바는 모든 객체가 모니터 락을 가지며,
synchronized 블록이 그 락을 획득하고 반납합니다. wait/notify로 조건 대기도 지원합니다.Q22. 데드락의 발생 조건 네 가지는?
상호 배제, 점유와 대기, 비선점, 순환 대기입니다. 네 가지가 모두 성립해야 발생하므로, 하나만 깨뜨려도 예방됩니다.
Q23. 데드락을 어떻게 처리하나요?
예방, 회피, 탐지 후 회복, 무시 네 가지가 있습니다. 예방과 회피는 자원 활용률을 떨어뜨리기 때문에, 실제 범용 OS는 대부분 무시하거나 탐지 후 회복을 택합니다.
Q24. 실무에서 데드락을 겪는다면 어떻게 대응하시겠어요?
가장 현실적인 예방책은 모든 트랜잭션이 동일한 순서로 락을 획득하게 만들어 순환 대기를 차단하는 것입니다. 여기에 락 타임아웃을 걸어 무한 대기를 끊고, 자바라면
jstack 스레드 덤프나 DB의 데드락 로그로 원인을 추적합니다.메모리와 가상 메모리
Q25. 가상 메모리가 필요한 이유는?
물리 메모리보다 큰 프로그램을 실행할 수 있게 하고, 프로세스마다 독립된 주소 공간을 제공해 보호와 격리를 보장하며, 더 많은 프로세스를 동시에 올릴 수 있게 해 CPU 이용률을 높입니다.
Q26. 페이징과 세그먼테이션의 차이는?
페이징은 고정 크기로 나누어 외부 단편화가 없는 대신 내부 단편화가 생기고, 세그먼테이션은 논리적 의미 단위로 나누어 내부 단편화가 없는 대신 외부 단편화가 생깁니다. 세그먼테이션은 의미 단위라서 권한 설정과 공유가 자연스럽습니다.
Q27. TLB는 왜 필요한가요?
페이지 테이블이 메모리에 있어 주소 변환에 메모리 접근이 한 번 더 필요합니다. TLB는 최근 변환 정보를 담는 캐시로, 히트하면 메모리 접근 한 번으로 끝나 주소 변환 오버헤드를 줄여줍니다.
Q28. 페이지 폴트가 발생하면 어떤 일이 일어나나요?
트랩이 발생해 커널 모드로 전환되고, 유효한 접근인지 확인한 뒤 디스크에서 해당 페이지를 빈 프레임으로 읽어옵니다. 페이지 테이블을 갱신한 후 중단된 명령을 다시 실행합니다. 빈 프레임이 없으면 교체 알고리즘으로 희생 페이지를 고릅니다.
Q29. 스래싱은 왜 발생하고 어떻게 해결하나요?
프로세스에 할당된 프레임이 워킹 셋보다 작아 페이지 폴트가 연쇄적으로 발생하는 상태입니다. CPU 이용률이 떨어지자 OS가 프로세스를 더 올리면서 상황이 악화되는 악순환이 핵심입니다. 워킹 셋 모델이나 PFF로 프레임을 조절하고, 근본적으로는 멀티프로그래밍 정도를 낮춰야 합니다.
Q30. 내부 단편화와 외부 단편화의 차이는?
내부 단편화는 할당된 공간 안에서 남는 낭비이고, 외부 단편화는 빈 공간의 총합은 충분하지만 연속되지 않아 사용하지 못하는 낭비입니다.
파일 시스템과 리눅스
Q31. inode란 무엇인가요?
파일의 메타데이터와 데이터 블록 위치를 담는 구조체입니다. 파일 이름은 inode가 아니라 디렉터리에 "이름 → inode 번호" 형태로 저장되며, 그래서 하나의 파일에 여러 이름(하드 링크)을 붙일 수 있습니다.
Q32. 서버에서 한글이 깨진다면 어디를 확인하시겠어요?
인코딩 불일치를 의심합니다. 파일 자체의 인코딩, JVM의 기본 인코딩, DB 문자셋, HTTP 응답 헤더의 charset을 순서대로 확인하고 모두 UTF-8로 통일합니다. MySQL에서 이모지가 깨진다면 utf8이 아닌 utf8mb4인지 확인합니다.
마무리
운영체제를 정리하면서 느낀 것은 결국 자원은 한정되어 있는데 어떻게 나눠 쓸 것인가라는 하나의 질문에 대한 답들이라는 점이었습니다. CPU를 나누는 방법이 스케줄링, 메모리를 나누는 방법이 페이징과 가상 메모리, 공유 자원을 나누는 방법이 동기화입니다.
서버에서 톰캣의 스레드 풀, 커넥션 풀의 최대 개수, 트랜잭션 락 순서, JVM 힙 설정까지 전부 운영체제에서 배운 원리 위에 올라가 있습니다.
서버에서 톰캣의 스레드 풀, 커넥션 풀의 최대 개수, 트랜잭션 락 순서, JVM 힙 설정까지 전부 운영체제에서 배운 원리 위에 올라가 있습니다.
'Computer Science' 카테고리의 다른 글
| [Network] 네트워크 총정리 (0) | 2026.08.06 |
|---|---|
| [자율주행 플랫폼] 5개 레이어로 정리한 인프라, 네트워크, V2X 용어 (1) | 2026.01.20 |
| 소켓 프로그래밍 완전 정복하기 (0) | 2025.03.07 |
| 부동소수점 연산 (1) | 2025.02.19 |