Posted On 2026년 03월 29일

복사의 신화: fork()가 진짜로 가져가는 것들

nobaksan 0 comments
여행하는 개발자 >> 기술 >> 복사의 신화: fork()가 진짜로 가져가는 것들

우리는 늘 무언가를 복사한다. Ctrl+C와 Ctrl+V의 손놀림이 익숙한 개발자들에게 ‘복사’는 너무나 당연한 행위다. 하지만 시스템 콜 수준에서 벌어지는 복사는 전혀 다른 차원의 문제다. 특히 fork()가 그렇다. 이 함수가 호출될 때 실제로 어떤 일이 벌어지는지 아는 사람은 드물다. 그저 ‘프로세스가 복제된다’는 추상적인 개념만 머릿속에 남아 있을 뿐이다. 그러나 그 이면에는 운영체제의 깊은 설계 철학과 하드웨어의 물리적 한계가 녹아들어 있다.

대부분의 설명은 fork()가 부모 프로세스의 메모리를 그대로 복사한다고 말한다. 하지만 이는 반만 진실이다. 실제로 일어나는 일은 훨씬 더 미묘하고, 때로는 기만적이다. 운영체제는 ‘복사’라는 단어를 쓰지만, 그 실체는 ‘공유’에 가깝다. 페이지 테이블의 엔트리들이 자식 프로세스에게도 동일하게 매핑되는 순간, 물리 메모리는 두 프로세스가 동시에 소유하게 된다. 이 순간부터 부모와 자식은 같은 데이터를 가리키지만, 그 데이터가 수정되는 순간에야 비로소 ‘진짜 복사’가 일어난다. 이를 Copy-on-Write(CoW)라고 부른다.

이 설계는 단순한 최적화가 아니다. 이는 메모리 자원의 효율성과 성능 사이의 절묘한 타협점이다. 만약 fork()가 정말로 모든 메모리를 즉시 복사한다면, 대규모 프로세스를 복제하는 데 드는 비용은 감당하기 어려울 것이다. 수백 메가바이트, 심지어 기가바이트에 달하는 메모리를 한순간에 복제하는 것은 비현실적이다. CoW는 이런 문제를 해결하면서도, 프로세스 간 격리를 유지하는 마법을 부린다. 수정되지 않는 한, 두 프로세스는 같은 물리 메모리를 공유하지만, 각각은 자신만의 독립된 메모리 공간을 가진 것처럼 착각한다.

운영체제는 거짓말을 잘한다. 우리에게는 복사가 일어나는 것처럼 보이지만, 실제로는 공유와 지연된 복사가 일어난다. 이 거짓말 덕분에 우리는 수십 년 동안 효율적인 멀티프로세싱을 누려왔다.

하지만 이 설계에는 대가가 따른다. CoW는 페이지 폴트(page fault)라는 새로운 복잡성을 시스템에 도입한다. 자식 프로세스가 공유 중인 메모리를 수정하려고 할 때, 운영체제는 비로소 복사를 수행한다. 이때 발생하는 페이지 폴트는 성능 저하의 원인이 될 수 있다. 특히 메모리 사용량이 많은 애플리케이션에서는 이 비용이 무시할 수 없는 수준으로 커진다. 또한, CoW는 메모리 단편화 문제를 악화시킬 수 있다. 복사가 지연되면서 물리 메모리에는 작은 조각들이 여기저기 흩어지게 되고, 이는 결국 시스템의 전반적인 성능을 저하시킨다.

이 모든 복잡성은 fork()의 본래 목적과도 관련이 있다. 유닉스 설계자들은 프로세스를 경량화하고, 새로운 프로그램 실행을 위한 기반으로 삼고자 했다. fork()exec()의 조합은 프로세스 생성을 단순화하면서도 강력하게 만들었다. 하지만 현대 시스템에서는 이 조합이 때로는 비효율적으로 작동하기도 한다. 예를 들어, 웹 서버가 요청마다 새로운 프로세스를 생성하는 경우, fork()의 오버헤드는 상당한 부담이 될 수 있다. 이 때문에 많은 현대 애플리케이션은 스레드나 이벤트 기반 모델로 전환하고 있다.

그렇다고 해서 fork()가 구식이라는 말은 아니다. 오히려 그 단순함과 강력함은 여전히 많은 시스템에서 빛을 발한다. 컨테이너 기술의 기반이 되는 프로세스 격리, 병렬 처리, 그리고 심지어 보안 메커니즘까지, fork()는 현대 컴퓨팅의 근간을 이루는 중요한 요소다. 문제는 우리가 이 함수를 너무 당연하게 여기고 있다는 점이다. 그 이면에 숨겨진 복잡성과 트레이드오프를 이해하지 못한 채, 그저 ‘복사’라는 단어에만 의존하고 있는 것은 아닌지 반문해볼 필요가 있다.

기술은 항상 트레이드오프의 산물이다. fork()도 예외는 아니다. 성능과 격리, 단순함과 복잡성 사이에서 균형을 잡는 이 함수는 운영체제 설계의 진수를 보여준다. 우리가 이 함수를 사용할 때마다, 그 이면에 숨겨진 수많은 결정과 타협을 떠올린다면, 시스템 프로그래밍의 깊이를 조금 더 이해할 수 있지 않을까.

이 글이 흥미로웠다면, 원문 What fork() Actually Copies도 읽어보길 권한다. 시스템 콜의 겉모습 뒤에 숨겨진 진실을 들여다보는 기회가 될 것이다.


이 포스팅은 쿠팡 파트너스 활동의 일환으로, 이에 따른 일정액의 수수료를 제공받습니다.

답글 남기기

이메일 주소는 공개되지 않습니다. 필수 필드는 *로 표시됩니다

Related Post

바보와 함께하는 기술의 아이러니

몇 년 전, 한 동네 카페에서 우연히 들었던 노래가 있다. 펫 샵 보이즈의 I'm with…

인공지능의 그림자 속에서 찾은 글쓰기의 윤리

왜 우리가 “글을 쓰는” 인간이 아니라 기계가 문장을 만들 때까지 기다려야 할까? 이 질문은 단순히…

스무 살의 나와 마주한 기술, 그리고 시간의 무게

기술은 언제나 미래를 약속한다. 더 빠르고, 더 편리하고, 더 연결된 세상을 그려보라고 손짓한다. 하지만 그…