1. CPU의 구성 요소(ALU, 제어장치, 레지스터)에 대해 설명해주세요.
CPU는 ALU, 제어장치, 레지스터로 구성됩니다.
ALU는 산술·논리 연산을 실제로 수행하고,
제어장치는 명령어를 해석해 각 장치에 신호를 보내는 지휘자 역할을 합니다.
레지스터는 CPU 내부의 가장 빠른 임시 저장 공간으로, PC가 다음 명령어 주소를 가리키는 등 각각 특수한 역할을 담당합니다.
꼬리질문
- 레지스터, 캐시, RAM의 속도와 용량 차이를 비교해주세요.
- 속도는 레지스터 > 캐시 > RAM, 용량은 그 반대입니다. 빠를수록 CPU에 가깝고 비싸서 용량이 작습니다.
- PC(Program Counter)는 언제 업데이트되나요?
- 명령어를 Fetch한 직후 자동으로 다음 주소로 증가하고, jump나 인터럽트 발생 시 특정 주소로 덮어씌워집니다.
- ALU가 연산 결과를 어디에 저장하나요?
- 범용 레지스터에 저장하고, 연산 결과의 상태(오버플로우, 0 여부 등)는 플래그 레지스터에 저장됩니다.
2. 프로세스가 실행될 때 메모리에는 어떤 영역(Code, Data, Heap, Stack)이 생성되나요?
프로세스가 실행되면 Code, Data, Heap, Stack 4가지 영역이 생성됩니다.
Code는 실행 명령어, Data는 전역·정적 변수, Heap은 런타임 동적 할당 영역, Stack은 함수 호출 시 지역변수와 리턴 주소를 저장합니다.
Heap은 위로, Stack은 아래로 자라며 서로 침범하면 overflow가 발생합니다.
꼬리질문
- 전역 변수와 지역 변수는 각각 어느 영역에 저장되나요?
- 전역 변수는 Data 영역에, 지역 변수는 Stack 영역에 저장됩니다. 전역 변수 중 초기화된 것은 Data, 초기화되지 않은 것은 BSS 영역에 들어갑니다.
- 메모리 누수(Memory Leak)는 어느 영역에서 주로 발생하나요?
- Heap 영역에서 발생합니다. 동적 할당 후 해제하지 않거나 참조를 계속 유지하면 메모리가 반환되지 않아 누수가 생깁니다.
- Java와 C에서 메모리 관리 방식이 어떻게 다른가요?
- C는 개발자가 직접 할당·해제를 관리하고, Java는 GC가 참조가 끊긴 객체를 자동으로 해제합니다. Java가 편리하지만 GC 실행 타이밍을 제어하기 어렵다는 단점이 있습니다.
3. Stack 영역과 Heap 영역의 차이점은 무엇인가요?
Stack은 컴파일러가 자동 관리하며 함수 호출 시 지역변수와 리턴 주소를 LIFO 구조로 빠르게 저장·해제합니다.
Heap은 런타임에 개발자가 동적으로 할당하는 영역으로, 크기가 유연하지만 속도가 느리고 메모리 누수 위험이 있습니다.
꼬리질문
- Stack Overflow는 왜 발생하나요?
- Stack 영역은 크기가 제한되어 있어서, 재귀 함수처럼 함수 호출이 너무 깊어져 스택 프레임이 한계를 초과하면 Stack Overflow가 발생합니다.
- 메모리 단편화(Fragmentation)란 무엇인가요?
- 메모리 할당·해제를 반복하면서 중간중간 작은 빈 공간이 흩어져, 총 여유 공간은 충분해도 연속된 공간이 없어 큰 메모리를 할당하지 못하는 현상입니다.
4. 캐시 메모리(Cache Memory)는 왜 사용하며, 지역성(Locality)이란 무엇인가요?
캐시 메모리는 CPU와 RAM의 속도 차이를 줄이기 위한 고속 임시 저장 장치입니다.
- 지역성 원리를 기반으로 동작
- 시간적 지역성은 최근 접근 데이터를 곧 다시 쓸 가능성이 높다는 것
- 공간적 지역성은 인접 주소 데이터도 곧 접근할 가능성이 높다는 원리
꼬리질문
- 캐시 라인(Cache Line)이란 무엇인가요?
- 캐시가 메모리에서 데이터를 가져오는 최소 단위(보통 64바이트)입니다. 한 번에 인접 데이터를 묶어 올려 공간적 지역성을 활용합니다.
- 배열과 링크드리스트 중 캐시 효율이 높은 자료구조는 무엇인가요? 이유는?
- 배열입니다. 연속된 메모리 구조라 캐시 라인에 여러 원소가 한꺼번에 올라오지만, 링크드리스트는 노드가 흩어져 있어 캐시 미스가 자주 발생합니다.
5. 캐시 히트(Cache Hit)와 캐시 미스(Cache Miss)는 무엇인가요?
- Cache Hit는 CPU가 필요한 데이터를 캐시에서 찾은 경우
- Cache Miss는 캐시에 없어 RAM까지 접근해야 하는 경우
- 미스가 발생하면 데이터를 캐시 라인 단위로 올려 이후 접근 속도를 높임
- 히트율을 높이려면 지역성 원리를 고려한 코드 작성이 중요함
꼬리질문
- 캐시 교체 정책(LRU, FIFO 등)에 대해 설명해주세요.
- 캐시가 꽉 찼을 때 어떤 데이터를 내보낼지 결정하는 정책입니다. 가장 오래 사용 안 된 것을 교체하는 LRU가 시간적 지역성을 잘 반영해 가장 널리 쓰입니다.
- 이중 for문에서 행 우선 vs 열 우선 접근이 성능에 미치는 영향은?
- 2차원 배열은 행 단위로 연속 저장되므로 행 우선 접근이 캐시 히트율이 높아 성능이 좋습니다. 열 우선 접근은 매번 캐시 미스가 발생해 느립니다.
6. CPU 스케줄링에서 Context Switching이란 무엇이며, 왜 비용이 발생하나요?
Context Switching 과정
- 인터럽트 또는 시스템 콜 발생
- 현재 프로세스의 Context를 PCB에 저장
- 스케줄러가 다음 실행할 프로세스 선택
- 선택된 프로세스의 Context를 PCB에서 복원
- 복원된 프로세스 실행
- Context Switching은 CPU가 실행 중인 프로세스를 바꿀 때 현재 상태를 PCB에 저장하고 다음 프로세스 상태를 복원하는 작업
- PCB 저장·복원 시간과 함께 이전 프로세스가 올려놓은 캐시가 무효화되어 캐시 미스가 증가하기 때문에 비용이 발생
- 스레드 전환은 메모리를 공유하므로 이보다 비용이 적음
꼬리질문
- Context Switching을 줄이는 방법은 무엇인가요?
- 프로세스 대신 스레드를 사용하거나, OS 개입 없이 전환하는 코루틴을 활용하는 방법이 있습니다.
- 프로세스와 스레드의 Context Switching 비용 차이는 왜 생기나요?
- 프로세스 전환은 메모리 공간이 바뀌어 페이지 테이블과 TLB까지 교체해야 하지만, 스레드는 메모리를 공유해 레지스터 상태만 교체하면 되므로 비용이 더 적습니다.
7. 인터럽트(Interrupt)란 무엇이고, 폴링(Polling)과 어떤 차이가 있나요?
- 인터럽트는 이벤트 발생 시 장치가 CPU에 신호를 보내 ISR을 실행하는 방식
- 폴링은 CPU가 장치 상태를 주기적으로 직접 확인하는 방식
- 인터럽트는 CPU 효율이 높고 반응이 빠르지만 구현이 복잡하며, 폴링은 단순하지만 CPU 자원을 낭비
- 인터럽트 발생 시 CPU는 어떤 순서로 처리하나요?
- 현재 상태를 저장 → 인터럽트 벡터에서 ISR 주소 확인 → ISR 실행 → 원래 상태 복원 순서로 처리됩니다.
- 소프트웨어 인터럽트와 하드웨어 인터럽트의 차이는?
- 하드웨어 인터럽트는 외부 장치가 발생시키고, 소프트웨어 인터럽트는 프로그램 내부에서 시스템 콜이나 예외 상황으로 발생합니다.
8. 시스템 콜(System Call)이란 무엇이며 왜 필요한가요?
- 시스템 콜은 유저 모드 프로그램이 파일 I/O, 네트워크 등 커널 기능을 사용하기 위해 OS에 요청하는 인터페이스
- 유저 모드에서 직접 하드웨어 접근을 막아 보안과 안정성을 보장
- 시스템 콜 호출 시 트랩이 발생해 커널 모드로 전환된 후 처리가 완료되면 유저 모드로 복귀합니다.
꼬리질문
- 커널 모드와 유저 모드를 왜 분리하나요?
- 모든 프로그램이 하드웨어에 직접 접근하면 보안과 안정성이 무너지기 때문입니다. 유저 모드를 분리해 OS를 통해서만 자원에 접근하게 강제합니다.
- fork()와 exec()의 차이는 무엇인가요?
- fork()는 현재 프로세스를 복사해 자식 프로세스를 생성하고, exec()는 현재 프로세스를 새 프로그램으로 교체합니다. 보통 fork() 후 자식에서 exec()를 호출하는 패턴으로 사용됩니다.
- 시스템 콜 호출 비용이 일반 함수 호출보다 비싼 이유는?
- 시스템 콜은 유저 모드에서 커널 모드로 전환하는 과정에서 레지스터 저장, 권한 검사, 스택 전환 등 추가 작업이 발생하기 때문에 일반 함수 호출보다 비쌉니다.
9. 컴파일 과정과 실행 과정을 설명해주세요. (전처리 → 컴파일 → 어셈블 → 링크 등)
1단계: 전처리 (Preprocessing) #include, #define, #ifdef 등 전처리 지시어를 처리합니다. 헤더 파일 내용을 소스에 삽입하고, 매크로를 치환합니다. 결과물: .i 파일 (확장된 C 소스)
2단계: 컴파일 (Compilation) 전처리된 소스 코드를 어셈블리 코드로 변환합니다. 문법 검사, 타입 체크, 최적화 등이 이뤄집니다. 결과물: .s 파일 (어셈블리 코드)
3단계: 어셈블 (Assembly) 어셈블리 코드를 기계어(오브젝트 파일)로 변환합니다. 결과물: .o 파일 (오브젝트 파일). 아직 다른 파일의 심볼(함수, 변수)은 미완성 상태.
4단계: 링킹 (Linking) 여러 오브젝트 파일과 라이브러리를 합쳐 하나의 실행 파일을 만듭니다. 미완성 심볼들의 주소를 연결(심볼 해석)합니다. 결과물: 실행 파일(.exe, ELF 등)
- 정적 링킹: 라이브러리 코드를 실행 파일에 포함 → 파일 크기 큼, 독립 실행 가능
- 동적 링킹: 런타임에 공유 라이브러리(.dll, .so)를 참조 → 파일 작음, 라이브러리 필요
컴파일 과정은 전처리 → 컴파일 → 어셈블 → 링킹 순입니다.
- 전처리는 헤더 삽입·매크로 치환
- 컴파일은 어셈블리 코드 변환
- 어셈블은 기계어 오브젝트 파일 생성
- 링킹은 여러 오브젝트 파일을 합쳐 최종 실행 파일을 만드는 단계
꼬리질문
- 정적 링킹과 동적 링킹의 차이와 장단점은?
- 정적 링킹은 라이브러리를 실행 파일에 포함시켜 독립 실행이 가능하지만 파일이 크고, 동적 링킹은 런타임에 공유 라이브러리를 참조해 파일이 작지만 라이브러리 의존성이 생깁니다.
- 인터프리터 언어(Python, JS)는 컴파일 언어와 어떻게 다른가요?
- 컴파일 언어는 실행 전 전체를 기계어로 변환해 빠르고, 인터프리터 언어는 실행 시 한 줄씩 해석해 느리지만 플랫폼 독립적입니다. Java는 바이트코드 + JVM + JIT로 중간 형태입니다.
10. 동기식(Synchronous)과 비동기식(Asynchronous)의 차이를 설명해주세요.
동기는 작업 완료를 기다린 후 다음을 진행하고, 비동기는 완료를 기다리지 않고 다음 작업을 진행하다가 완료 시 콜백 등으로 결과를 받는 방식입니다. 비동기는 I/O 대기 시간에 CPU를 다른 작업에 활용할 수 있어 처리량이 높습니다.
꼬리질문
- 비동기 방식의 단점은 무엇인가요?
- 코드 흐름이 비선형적이라 가독성과 디버깅이 어렵고, 콜백 중첩으로 콜백 지옥이 생길 수 있습니다. 또한 실행 순서가 보장되지 않아 경쟁 조건 같은 동시성 문제도 발생할 수 있습니다.
11. Blocking과 Non-Blocking의 차이를 설명해주세요.
Blocking/Non-Blocking은 호출된 함수가 호출한 함수의 제어권을 가져가느냐의 문제입니다. 동기/비동기와 혼동하기 쉬우므로 구분이 중요
Blocking 함수를 호출하면 제어권이 호출된 함수로 넘어가고, 작업이 완료될 때까지 호출한 쪽은 아무것도 못 합니다. 결과가 반환될 때 제어권이 돌아옵니다.
Non-Blocking 함수를 호출해도 제어권이 호출한 쪽에 남아있어 다른 작업을 계속할 수 있습니다. 호출된 함수는 즉시 반환(결과가 없으면 없다고 즉시 반환)합니다.
동기/비동기 vs Blocking/Non-Blocking 조합
| Blocking | Non-Blocking | |
| Synchronous | 결과 기다리며 대기 (일반적인 함수 호출) | 결과 날 때까지 반복 확인 (Busy-wait) |
| Asynchronous | 비효율적 조합 (드묾) | 요청 후 다른 일 하다가 완료 통보 받음 (가장 효율적) |
### 동기/비동기 vs Blocking/Non-Blocking
두 개념은 비슷해 보이지만 바라보는 관점이 다릅니다.
동기/비동기는 작업의 결과를 언제 처리하느냐의 문제입니다. 동기는 결과가 날 때까지 기다렸다가 처리하고, 비동기는 결과를 기다리지 않고 나중에 콜백이나 이벤트로 처리합니다.
Blocking/Non-Blocking은 함수를 호출했을 때 제어권, 즉 다음 코드를 실행할 권리를 언제 돌려받느냐의 문제입니다. Blocking은 호출한 함수가 완료될 때까지 제어권을 넘겨줘 호출한 쪽이 대기하고, Non-Blocking은 즉시 제어권을 돌려줘 호출한 쪽이 계속 진행할 수 있습니다.