최근 CS 기술 면접 대비에 시간을 많이 쓰고 있다.
여러 자료 + 이전 강의에서 본 내용을 보면서 GPT와 모의면접을 하고 있는데, 생각보다 시간이 엄청 쓰인다.
이렇게 시간을 많이 쓰는데 면접이 끝나고, 붙으면 좋겠지만 혹여 떨어지면 지금 준비하는 이 시간이 아무것도 안한 시간이 될까봐.
그리고 분명히 작년 11월 즈음 면접 준비를 하긴 했는데, 기억에서 날라가버렸다..
뭐라도 남겨보자는 심정과 노션에 흩어진 글을 조금이라도 정제해보자는 마음으로 이 포스팅을 시작하였다.
주로 GPT + VSFe 님의 기술면접 질문 모음집을 참고하였다.
질문과 답변 모두 신입 개발자의 입장에서 쓰여진 것이니 오류나 말이 안 맞는 것이 있을 수 있다. 혹은 더 좋은 답변이 있을 수 있다.
이를 발견하여 제게 알려주신다면 커피..라도 한잔 사드리고 싶을 것 같다. 🙇🏻♂️
시스템 콜이 무엇인지 설명해 주세요. 왜 필요한가요?
시스템 콜(System Call)은 운영체제의 커널 기능을 사용자 프로그램이 사용할 수 있도록 해주는 인터페이스
입니다.
예를 들어, 파일을 읽거나, 프로세스를 생성하거나, 네트워크에 데이터를 보내는 등의 작업은 모두 하드웨어 자원에 접근해야 하므로사용자 프로그램이 직접 접근할 수 없고, 반드시 커널을 통해서만 수행해야 합니다.
시스템 콜이 필요한 이유는 보안성과 안정성 때문입니다. 안정성이란, 다른 프로세스의 메모리를 침범하지 안도록 하거나, 권한과 접근을 제어하고, 명확한 성공/실패여부로 오류처리나 예외처리를 합니다.
시스템 콜도 결국 커널 코드니까, 버그 나면 위험하지 않나요?
네. 따라서 더 엄격하고, 시스템 콜 경로도 최소화하도록 설계되빈다. 또 사용자프로그램과 격리되어 있습니다.
시스템 콜과 일반 함수 호출의 차이점은 무엇인가요?
가장 큰 차이는 모드 전환과 접근 권한입니다.
일반 함수는 사용자 모드에서 실행되지만, 시스템콜은 커널모드를 사용하기 위해, 특별한 인터럽트(트랩)을 통해 커널 영역으로 전환됩니다.
이때, 보안, 권한 확인, 문맥 전환 등의 부가 작업이 있습니다.
오버헤드가 있지만, os의 보호를 받으며 안전하게 자원에 접근합니다.
시스템 콜 오버헤드를 줄이는 방법은 무엇인가요?
- Batching : 여러 콜을 한번에 처리하거나, 버퍼링 후 일괄 처리
- Lazy Evaluation : 예를 들어 mmap은 실제 메모리 할당을 지연시켜, 시스템 콜 횟수를 줄인다.
- 비동기 I/O : epoll(), io)uring 등은 블로킹 없이도 다수의 I/O 처리를 효율적으로 수행해 시스템 콜 빈도를 줄입니다.
- vDSO : 시간 조회처럼 자주 쓰이는 시스템 콜은 유저 공간에서 커널 함수 주소를 노출시켜, 커널 진입 없이 호출 가능합니다.
시스템 콜 없이도 커널 기능을 우회해서 사용하는 방법이 있나요?
대부분의 커널 기능은 시스템 콜을 통해서만 접근하도록 제한되어 있습니다.
하지만 일부 자원이나 정보는 커널이 사용자 공간에 미리 노출시켜 놓기도 합니다.
vDSO(Virtual Dynamic Shared Object)
는 gettimeofday()
같은 시간 관련 기능을 커널 진입 없이 호출할 수 있도록 유저 공간에서 함수 포인터를 제공합니다.
최근 운영체제들은 시스템 콜을 더 빠르게 하기 위해 어떤 기술을 도입하나요?
sysenter
/ sysexit
명령어: 기존 int 0x80
인터럽트 호출보다 훨씬 빠른 CPU 명령어로, 커널 진입 비용을 줄임
vDSO (Virtual Dynamic Shared Object): 커널이 제공하는 시간 정보 등을 유저 공간 라이브러리로 노출해서 커널 진입 없이 직접 호출.
BPF (Extended BPF): 특정 이벤트 처리나 모니터링 시, 커널 진입 없이 안전하게 실행되는 작은 코드 조각을 유저 공간에서 등록.
o_uring: 최근 리눅스 커널에서 제공하는 비동기 I/O 인터페이스로, 시스템 콜을 미리 큐에 등록해두고 한 번에 처리.
우리가 사용하는 시스템 콜의 예시를 들어주세요.
open()
,read()
,write()
,close()
– 파일 입출력- Node.js에서
fs.readFile()
을 호출하면 내부적으로open → read → close
시스템 콜을 수행합니다.
fork()
,exec()
,wait()
– 프로세스 제어fork()
는 새 프로세스를 복제하고,exec()
은 새로운 프로그램을 실행하며,wait()
은 자식 프로세스가 종료될 때까지 대기합니다.- 예: 쉘의 작동 구조, 서버에서 새로운 요청을 처리할 때,
fork()
로 워커 프로세스를 생성하는 구조.
socket()
,bind()
,listen()
,accept()
,connect()
– 네트워크 통신- TCP/UDP 연결 설정과 데이터 송수신은 모두 시스템 콜을 통해 이루어집니다.
- 예: Node.js의
http.createServer()
는 내부적으로socket → bind → listen → accept
의 시스템 콜 흐름을 사용합니다. 소켓 생성 → bind는 Ip/Port 할당 → 연결 대기 시작 → 연결 수락
gettimeofday()
,clock_gettime()
– 시스템 시간 조회- 시간을 확인하는 것도 단순한 함수처럼 보이지만, 실제로는 커널로부터 현재 시간을 요청하는 시스템 콜입니다.
- 성능을 위해
vDSO
기반으로 유저 공간에서 처리되기도 합니다.
mmap()
은 DB, 미디어 플레이어, 브라우저 렌더링에서 많이 사용. 메모리 관련
네트워크 통신은 왜 커널에 구현되어있어?
하드웨어 제어는 특권 권한이 필요, 공유 자원(네트워크 스택)을 중앙에서 관리, 패킷 수신과 전송에 대한 빠른 응답과 제어, 보안 검증 및 방화벽 적용
파일을 열고 내용을 읽는 시스템 콜의 흐름은 어떻게 되나요?
open(path, flags)
– 파일 열기
파일 시스템을 따라 탐색, 열기에 성공하면 커널 내부에서 **파일 디스크립터를 생성, 프로세스의 파일 디스크립터 테이블에 파일 등록 → 유저는 fdaksdmfh read, close 호출
read(fd, buffer, size)
– 내용 읽기
커널은 fd
를 기준으로 열려 있는 파일 객체(VFS inode)를 찾고, 요청된 size
만큼의 데이터를 읽어, 유저 공간의 buffer
에 복사해줍니다.
파일을 업로드하거나 다운로드할 때 시스템 콜은 어떻게 관여하나요?
서버 입장에서 보는 흐름:
- 클라이언트가 HTTP 요청 생성→ 내부적으로
socket()
,connect()
등의 시스템 콜 호출 - → 브라우저 내부에서 TCP 소켓을 열어 서버와 연결
- 요청 수신: 서버에서 데이터 수신→ 업로드된 파일의 이진 데이터는 바이트 스트림으로 들어옴
- → 서버는
accept()
로 연결 수락 후,read()
또는recv()
시스템 콜로 요청 본문을 읽음 - 서버가 업로드된 데이터를 파일로 저장→
write()
로 디스크에 저장서버 입장에서 보는 흐름:- 클라이언트가 파일 요청 (예: GET /image.jpg)
- → HTTP 요청 수신:
accept()
,read()
로 요청 바디 수신 - 서버가 디스크에서 파일을 읽음→
read()
또는mmap()
으로 메모리에 로드 - →
open()
으로 파일 열고 - 파일 데이터를 네트워크로 전송→ 고성능 환경에서는
sendfile()
사용 → zero-copy 방식으로 커널에서 바로 전송 - →
send()
또는write()
로 소켓에 바이트 전송
- → 저장 완료 후
close()
- →
open()
으로 저장할 파일 생성
fork()
시스템 콜과 exec()
시스템 콜의 차이는 무엇인가요?
fork()는 프로세스를 복제하고,(복제되었기 때문에 fork()
이후의 코드가 부모와 자식에서 각각 따로 실행됨.)
(반환값이 달라서 부모는 자식 PID를, 자식은 0을 반환받음 → 이를 통해 부모/자식 분기 가능)
exec()는 기존 프로세스를 새로운 프로그램으로 덮어씁니다.(프로세스 ID는 유지되지만, 메모리 공간, 코드, 스택 등이 모두 대체됨. 보통 fork()
이후에 호출해서, 자식 프로세스가 다른 프로그램을 실행할 때 사용됨.)
보통 함께 사용되어, 자식 프로세스가 새 프로그램을 실행하도록 할 때 쓰입니다.
그럼 exec 하면 실행중인 프로세스가 새로운 프로그램 파일로 바뀌는거야?
exec()는 기존 프로세스의 메모리 구조를 모두 제거하고,
새로운 프로그램의 코드와 데이터를 로드하여 실행시키는 시스템 콜입니다.
이때 프로세스 ID는 유지되지만, 실행 흐름과 메모리 상태는 전부 초기화됩니다.
wait()
시스템 콜은 어떤 상황에서 사용되나요?
부모 프로세스가 자식 프로세스의 종료를 기다릴 때 사용된다.
주로 fork한 자식 프로세스의 종료를 부모가 블로킹 상태로 대기하는데, 자식 프로세스의 좀비 프로세스를 막고자한다.
좀비 프로세스란 os가 정리하지 못한 프로세스의 종료 상태입니다. 커널이 이를 회수하지 못한 것으로, PID, PCB 등을 점유합니다.
프로세스를 생성할 때 사용되는 시스템 콜을 설명해 주세요.
우선 fork로 부모 프로세스를 복사해 새 자식 프로세스를 생성합니다. 자식이 exec를 호출하면 자신을 완전히 새로운 프로그램으로 덮어 씌워, PID는 유지되지만 메모리 구조와 코드가 새 프로그램이 됩니다.
왜 이렇게 fork, exec 하나요?
자식이 부모와 동일한 환경에서 시작하도록. 이후 자식이 원하는 설정을 바꾸고 exec 한다.
생성과 실행을 분리해 더 유연하게 자식을 설정하고 제어한다.
fork는 프로세스를 생성하기 위한 틀, exec는 그 틀에서 어떤 프로그램을 실행할지 유연히 결정
→ 어떻게 만들까와 무엇을 실행할까를 분리. 처음엔 부모와 같지만 다른일을 하도록 바꿔 쓴다
예를 들어, shell에서 bash는 입력을 받는다. fork로 자신을 복제해서 자식 프로세스를 생성하고, 자식은 la -al 명령어를 입력받아 exec(’ls’, [”-al”])를 호출한다. 그럼 ls 프로그램으로 바뀌고, 부모인 bash는 wait으로 자식의 종료를 기다린다.
bash는 계속 살아있고, ls는 자식에서 독립적으로 실행된다.
이렇게 설계된 이유는 하나의 생성 API로 어떤 프로그램이든 실행 가능해 더 유연한 조합, exec 실행시 환경 설정이 가능하여 깨끗하게 다른 프로그램 실행 가능하다. 결국 fork는 언제나 프로세스 복제, exec는 언제나 새로운 프로그램 로드로 구현이 단순하고 재사용 가능하다.
시스템 콜이, 운영체제에서 어떤 과정으로 실행되는지 설명해 주세요.
시스템 콜로 트랩을 발생시켜 커널 모드로 전환하고, 시스템콜 번호를 기반으로 커널 함수가 시행된 후, 사용자 공간으로 복귀해 레지스터에 저장된 결과를 받는다.
운영체제의 Dual Mode 에 대해 설명해 주세요.
유저모드와 커널모드로 나뉩니다.
사용자 프로그램이 실수나 악의적으로 시스템 자원을 망가뜨리지 않게 하기 위함이고, 한 프로그램이 망가져도 OS는 계속 살아있어 안정적으로 하기 때문입니다.
서로 다른 시스템 콜을 어떻게 구분할 수 있을까요?
시스템 콜 번호가 있고, 미리 정의된 시스템 콜 번호를 특정 레지스터에 저장 후 명령어를 통해 커널모드로 진입합니다.
번호인 이유는 빠르게 배열 인덱스로 접근 가능하기 때문입니다.
시스템 콜의 실행 과정에서 문맥 전환(Context Switch)이 일어나나요?
문맥 전환이란, 현재 실행중인 프로세스나 스레드를 중단하고 다른 실행 정보를 복구, 전환하는 작업입니다.
(CPU의 레지스터, 프로그램 카운터, 스택 포인터 등)
시스템콜은 모드전환이므로 문맥전환은 아닙니다. 즉 같은 프로세스, 같은 CPU 입니다.
하지만 문맥전환이 발생하는 경우도 있습니다.
- 블로킹 시스템콜일 경우, 현재 프로세스는 대기 상태가 되고, 커널은 다른 프로세스로 문맥 전환
- 시스템 콜 도중 인터럽트로 인한 CPU 스케줄링
- 시스템콜이 다른 프로세스를 wake up or fork할 경우, 스케줄러가 개입
REST API 호출 시 내부적으로 시스템 콜이 사용되나요?
요청 시, 내부적으로 socket, connect, write, send, read, close 등의 시스템콜이 사용되어,
커널 공간에서 NIC으로 전송한다.
응답 도착 시 인터럽트가 발생한다.
WAS(Web Application Server)에서 시스템 콜 호출이 병목으로 이어질 수 있는 사례는?
WAS는 파일 IO, 네트워크 처리, 프로세스 등 다양한 작업을 합니다.
정적 파일 제공시, open, read 등 호출이 잦아지면, VFS(파일 디스크립터 관리 구조)에서 병목이 발생합니다.
이는 파일 캐싱(메모리 상 유지), 파일 핸들 재사용 등으로 해결합니다.
요청마다 새 프로세스를 생성하면 fork, exec로 전체 메모리 공간 재로딩하는 등 비용이 큽니다.
프로세스 풀, 스레드 풀을 사용하거나 WAS 내부 로직에서 child process 남용을 방지합니다.
블로킹 방식으로 IO를 처리하면 스레드 낭비이고, 리소스 풀이 고갈되어 전체 서버가 느려집니다.
→ non block이나 Event-driven으로 바꿉니다.
또 요청마다 로그를 남기면 write, fsync 남용으로 병목이 생겨, 로그 비동기 처리 등의 방식이 있습니다.
시스템 콜 호출이 많아질수록 성능 저하가 발생할 수 있는 이유는 무엇인가요?
모드 전환, CPU 파이프라인 플러시, 커널락 경쟁, 메모리 복사 비용 등이 누적되며 성능 저하 발생 가능합니다.
대규모 트래픽 처리 중 시스템 콜 병목이 발생했다면, 어떤 지표를 보고 진단할 수 있을까요?
시스템 콜 호출 횟수가 높다면 불필요한 시스템콜 남발한다는 것입니다.
특정 시스템콜이 비정상적으로 오래 걸린다면 커널 락 경합, IO 대기 등의 가능성이 있습니다.
하나의 시스템 콜이 blocking일 경우 대규모 시스템에 어떤 문제가 발생할 수 있나요?
Blocking 이라면 해당 프로세스는 다음 작업을 하지 못하고 대기합니다. 이는 리소스를 점유하고 있어 신규 요청을 거부될 수 있습니다.
하나의 요청이 블로킹되면, 해당 요청을 기다리는 다른 요청들도 줄줄이 지연됩니다. 이게 또 공유 자원을 점유 중이면 전체 서비스가 병목, 죽을 수도 있습니다.
그럼 TPS가 감소하고 문맥 전환이 많아지며 처리량은 그대롲만 CPU 사용률만 높아질 수 있습니다.
고성능 서버에서 시스템 콜 오버헤드를 줄이기 위한 방법은 무엇이 있나요?
- 예:
mmap()
,epoll()
,sendfile()
등 zero-copy 방식
batching으로 여러개를 한번에 하여 시스템 콜 수를 감소시킨다.
zero copy : 파일을 복사 없이 메모리 매핑
커널 우회 IPC
브라우저 환경에서는 시스템 콜을 직접 사용할 수 없는데, 그렇다면 어떤 방식으로 OS와 통신하나요?
웹 API(fetch()) → 브라우저 엔진(크로미움의 블링크)이 시스템 콜
웹 브라우저가 OS 리소스를 안전하게 사용하는 구조는 어떻게 되어 있나요?
우선 JS가 직접 시스템콜을 하지 못하고, 브라우저의 렌더러 프로세스에서 실행된다.
탭마다 별도의 프로세스를 사용하여, 하나의 탭이 공격당해도 다른 탭, OS에 영향이 없다.
렌더러는 IPC 메시지로 브라우저 프로세스에 전달하고, 브라우저 프로세스가 검증 후 OS 시스템콜을 한다.
시스템 콜 인터페이스(System Call Interface, SCI)는 어떤 역할을 하나요?
라이브러리 함수로 호출 - read, write, open 등 glibc의 read(fd, buf, len);
직접 호출 - syscall(SYS_read, fd, buf, len)
시스템 콜을 래핑(wrapping)한 고수준 API와의 관계는 어떤가요? (ex. POSIX 라이브러리)
- "프로세스와 스레드의 차이점은?"
- "프로세스끼리는 어떻게 통신하나요?"
- "같은 프로그램으로 여러 프로세스를 만들 수 있나요?"
스레드는 하나의 프로세스 내부에서 생성된 실행 흐름. 동일 프로세스의 코드, 데이터, 힘을 공유하고, 스택만 독립적으로 가집니다. 따라서 서로 같은 전역 변수와 힙 객체에 접근하여 프로세스 간 통신보다 빠르고 효율적입니다. 생성비용도 프로세스를 만드는 것보다 낮습니다.
하지만 동시에 동기화 문제가 발생할 위험도 있습니다.
또 한 스레드가 죽으면 전체에 영향이 가능.
왜 clone()
이 스레드 생성에 사용되나요?
fork와 달리 프로세스의 자원 일부를 공유하며 새로운 실행 흐름을 만든다.
공유할 자원을 세세히 지정한다. 메모리를 공유.
'CS지식' 카테고리의 다른 글
[자료구조] 연결리스트 (0) | 2025.04.20 |
---|---|
[알고리즘] 시간복잡도와 공간복잡도 (2) | 2025.04.18 |
[네트워크] 서버3계층(3-Tier) 면접질문 (4) | 2025.04.17 |
[네트워크] 쿠키, 세션, 토큰 면접질문 (2) | 2025.04.16 |