---
title: "리눅스 커널에서 fork() + exec()를 넘어서려는 새 논의가 나옴"
published: 2026-06-06T14:34:20.000Z
canonical: https://jeff.news/article/3846
---
# 리눅스 커널에서 fork() + exec()를 넘어서려는 새 논의가 나옴

리눅스 커널 쪽에서 반복적인 프로세스 실행 비용을 줄이기 위한 spawn template 패치셋이 논의됐지만, 리뷰 과정에서 더 근본적인 방향으로 posix_spawn()을 제대로 지원하자는 흐름으로 바뀜. 초기 벤치마크 개선폭은 약 2%였고, 최종적으로는 pidfd 기반으로 빈 프로세스를 만들고 설정하는 API가 더 낫다는 의견이 힘을 얻음.

## 오래된 fork() + exec() 패턴이 다시 도마 위에 오름

- 리눅스에서 프로세스를 띄우는 고전 패턴은 fork()로 자식 프로세스를 만들고, 곧바로 exec()로 실행 파일을 바꾸는 방식임
  - fork()는 부모 프로세스의 메모리와 상태를 자식 쪽에 복사하는 비싼 시스템 호출임
  - 커널이 수년간 최적화를 많이 했지만, 구조적으로 “일단 복사하고 나중에 버리는” 비용은 남아 있음
  - 특히 fork() 직후 exec()가 오면, 애써 준비한 자식 프로세스 메모리 상태 대부분을 바로 폐기하게 됨

- 이번 패치셋은 이 반복 비용을 줄이려고 spawn template이라는 아이디어를 제안함
  - 예를 들어 어떤 프로그램이 Git 실행 파일을 반복 호출해서 저장소 정보를 읽는 상황을 상상하면 됨
  - 매번 같은 실행 파일을 띄운다면, 실행 파일 관련 준비 정보를 템플릿으로 만들어 캐시해두자는 접근임

## spawn template이 하려던 일

- 제안된 API는 spawn_template_create()로 실행 파일 템플릿을 먼저 만드는 구조임
  - 실행 파일은 파일 디스크립터(execfd)나 절대 경로(filename) 중 하나로 지정함
  - 커널은 해당 실행 파일을 열고, 이후 더 빨리 실행하는 데 필요한 정보를 캐시함
  - 반환값은 템플릿을 가리키는 파일 디스크립터임

- 실제 실행 시점에는 spawn_template_spawn()에 인자와 환경, 파일 디스크립터 조작 같은 정보를 넘김
  - argv는 프로그램 인자 목록, envp는 환경 변수 목록임
  - actions에는 자식 프로세스에서 파일 디스크립터를 닫거나 복제하거나, 작업 디렉터리를 바꾸거나, 시그널 처리를 바꾸는 작업이 들어감
  - 예를 들어 자식에서 fd 4를 닫고 싶으면 SPAWN_TEMPLATE_ACTION_CLOSE와 fd 4를 액션에 넣는 식임

```mermaid
sequenceDiagram
    participant 앱 as 애플리케이션
    participant 커널 as 리눅스 커널
    participant 템플릿 as Spawn 템플릿
    participant 자식 as 새 프로세스
    앱->>커널: spawn_template_create()
    커널->>템플릿: 실행 파일 정보 캐시
    앱->>커널: argv, envp, actions 전달
    커널->>템플릿: 캐시된 실행 정보 조회
    커널->>자식: spawn_template_spawn()으로 실행
```

- 성능 개선은 약 2%로 제시됨
  - 숫자만 보면 “겨우?” 싶을 수 있음
  - 하지만 같은 실행 파일을 매우 자주 띄우는 워크로드라면 2%도 누적 비용에서는 의미가 있을 수 있음
  - 커널 패치 논의에서는 이런 작은 비용도 충분히 진지하게 다뤄짐

> [!IMPORTANT]
> 이 패치셋의 벤치마크 개선폭은 약 2%였음. 큰 숫자는 아니지만, 자식 프로세스를 자주 띄우는 빌드 도구나 저장소 분석 도구에서는 이런 비용이 반복해서 쌓임.

## 리뷰는 더 근본적인 방향으로 틀어짐

- Mateusz Guzik은 fork + exec 관용구 자체가 문제라고 강하게 지적함
  - spawn template은 exec 쪽 일부를 최적화하지만, 정작 비용의 큰 부분인 fork()는 그대로 둠
  - 그의 핵심 주장은 현재 프로세스를 복사하지 말고, 처음부터 깨끗한 새 프로세스를 만드는 방향으로 가야 한다는 것임

- Christian Brauner도 목표 자체에는 긍정적이었지만, API 방향은 pidfd 위에 쌓는 쪽을 제안함
  - pidfd_open()에 빈 프로세스를 만드는 옵션을 추가하는 식의 구상을 언급함
  - 이후 pidfd_config() 같은 새 시스템 호출로 환경, 실행 이미지, 설정을 단계적으로 구성하는 방식임
  - fsconfig()가 파일 시스템 설정을 빌더처럼 구성하는 것과 비슷한 발상으로 보면 됨

- 중요한 목표는 user space에서 제대로 된 posix_spawn()을 구현할 수 있게 하는 것임
  - posix_spawn()은 fork()/exec() 패턴을 대체하기 좋은 인터페이스임
  - 하지만 현재 구현은 내부적으로 fork()와 exec()를 감추는 경우가 많아서 근본적인 비용을 없애진 못함
  - 커널이 빈 프로세스 생성과 설정을 네이티브하게 지원하면, posix_spawn()이 진짜 대체재가 될 수 있음

- 결론적으로 spawn template 자체는 커널에 들어가지 않을 가능성이 커짐
  - 제안자인 Chen도 Brauner가 스케치한 pidfd 기반 API가 더 나은 방향이라는 데 동의함
  - 앞으로의 작업은 spawn template보다는 proper posix_spawn() 구현을 가능하게 하는 쪽으로 갈 전망임

---
## 기술 맥락

- 여기서 핵심 선택은 “기존 fork()/exec() 경로를 살짝 빠르게 만들 것인가, 프로세스 생성 모델을 새로 설계할 것인가”예요. spawn template은 앞쪽 선택에 가깝고, pidfd 기반 빈 프로세스 생성은 뒤쪽 선택에 가까워요.

- fork()가 비싼 이유는 새 프로그램을 실행하려는 순간에도 일단 현재 프로세스를 복제하는 모델에서 출발하기 때문이에요. copy-on-write 같은 최적화가 있어도, 커널이 다뤄야 하는 프로세스 상태와 검증 경로는 여전히 복잡하거든요.

- pidfd 기반 접근이 매력적인 이유는 프로세스를 파일 디스크립터처럼 안정적으로 붙잡고, 실행 이미지나 환경 같은 설정을 단계적으로 넣을 수 있기 때문이에요. 이렇게 되면 user space의 posix_spawn()이 fork()/exec()를 감춘 래퍼가 아니라, 커널 기능을 제대로 쓰는 인터페이스가 될 수 있어요.

- 이 변화는 셸 하나 빠르게 띄우는 수준보다 범위가 넓어요. Git을 반복 호출하는 도구, 빌드 시스템, 서버 런처처럼 프로세스를 자주 만드는 프로그램에서는 작은 시스템 호출 비용과 설계 차이가 전체 지연 시간에 계속 누적되거든요.

## 핵심 포인트

- fork() 뒤에 바로 exec()를 호출하는 패턴은 복사한 프로세스 상태를 곧바로 버리기 때문에 구조적으로 비효율적임
- 제안된 spawn template은 같은 실행 파일을 반복 실행하는 애플리케이션에서 실행 정보를 캐시해 비용을 줄이려는 접근임
- 벤치마크상 개선폭은 약 2%로 크진 않지만 Git 같은 실행 파일을 반복 호출하는 패턴에서는 의미가 있을 수 있음
- 리뷰어들은 비용의 핵심이 fork() 자체에 있으므로 깨끗한 새 프로세스를 만드는 방향이 더 낫다고 지적함
- Christian Brauner는 pidfd_open()과 pidfd_config() 같은 pidfd 기반 빌더 API로 user space posix_spawn() 구현을 지원하는 방향을 제안함

## 인사이트

이 논의의 재미는 “2% 빠른 fork/exec 캐시”가 아니라, 리눅스가 오래된 프로세스 생성 관성을 어디까지 뜯어고칠 수 있느냐에 있음. 서버, 빌드 도구, Git 호출 많은 프로그램처럼 자식 프로세스를 자주 띄우는 시스템에서는 작은 syscall 설계 차이가 은근히 누적됨.
