프로세스가 종료될 때 마지막 문장의 실행을 끝내고 exit() 시스템콜을 사용하여 운영체제에게 자신의 삭제를 요청하면서 종료된다. 부모 프로세스는 wait() 시스템콜을 사용해 자식 프로세스의 종료를 기다릴 수 있다.
프로세스가 종료되면 메모리, CPU 등 사용하던 실행 리소스는 OS가 회수해간다. 하지만 프로세스의 종료 상태가 저장되는 프로세스 테이블의 해당 항목은 부모 프로세스가 wait()을 호출할 때까지 남아있게 된다. 즉, 종료는 되었지만 부모 프로세스가 아직 wait()을 호출하지 않은 프로세스를 좀비 프로세스라고 한다.
모든 프로세스는 종료 후 좀비 상태가 되지만 일반적으로 아주 짧은 시간 머무르다가 부모 프로세스의 wait() 호출에 의해 프로세스 식별자와 프로세스 테이블의 해당 항목이 OS에 반환된다. 좀비 프로세스는 메모리나 CPU 같은 실행 리소스를 소모하지 않고 프로세스 테이블 엔트리만 점유하기 때문에 소수의 좀비 프로세스는 큰 문제가 되지 않는다. 다만 좀비 프로세스가 많아지면 프로세스 식별자(PID)가 고갈될 수 있으므로 주의가 필요하다.
좀비 프로세스 확인
좀비 프로세스 필터링
ps aux | egrep "Z|defunct"
meatsby@lima-default:~$ ps aux | egrep "Z|defunct"USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMANDroot 1970 0.0 0.0 0 0 ? Z 17:50 0:00 [sshd] <defunct>meatsby 5053 0.0 0.0 6904 1884 pts/2 S+ 17:55 0:00 grep -E --color=auto Z|defunct
좀비 프로세스는 ps aux | egrep "Z|defunct" 명령어로 필터링하여 확인할 수 있다.
<type> = soft (시작 시 받는 값) / hard (setrlimit 으로 올릴 수 있는 상한). soft ≤ hard
<item> = nofile (fd) / nproc (프로세스) / memlock / stack / cpu 등
<value> = 정수 또는 unlimited
기본값이 낮다
대부분 배포판이 nofile soft 1024 / hard 4096. multi-connection 서버(JVM, Nginx, Node.js, DB 클라이언트) 는 금방 부족 → EMFILE: Too many open files → 새 연결 거부. 흔한 튜닝 = 65530 (16-bit 한도 65535 직전).
systemd 가 PAM 을 우회
systemd 가 띄우는 서비스(systemctl start nginx) 는 PAM login 을 안 거치므로 limits.conf 가 안 먹는다. 대신 unit 파일에:
[Service]LimitNOFILE=65530LimitNPROC=4096
또는 전역 default = /etc/systemd/system.conf 의 DefaultLimitNOFILE=. 위 ## 운영 명령어·## 리소스 제어 와 연결.
컨테이너 환경
Docker = docker run --ulimit nofile=65530:65530 ...
Kubernetes = 직접 pod 에 ulimit 설정 옵션이 없음. host 의 limit 이 ceiling, 컨테이너는 그 안에서 inherit. host 노드에 LimitNOFILE 을 미리 올려둬야 함.
컬럼 = VIRT 가상 메모리 / RES 실제 메모리 / S 상태(S sleep, R running, Z zombie).
sar
root@lima-default:~# sarLinux 6.17.0-6-generic (lima-default) 12/22/25 _aarch64_ (4 CPU)18:05:28 LINUX RESTART (4 CPU)18:10:36 CPU %user %nice %system %iowait %steal %idle18:20:36 all 0.06 0.00 0.12 0.00 0.00 99.8218:30:36 all 0.07 0.00 0.12 0.00 0.00 99.8118:40:36 all 0.08 0.00 0.13 0.00 0.00 99.7918:50:36 all 0.09 0.00 0.14 0.00 0.00 99.77Average: all 0.08 0.00 0.13 0.00 0.00 99.80
sysstat 패키지. cron 으로 주기적 수집되는 시스템 통계를 사후 조회.
top 이 “지금” 이라면 sar 는 “지난 X 분 평균” — 사후 트러블슈팅용.
옵션 = -u CPU / -r 메모리 / -d 디스크 / -n DEV 네트워크 인터페이스.
systemd 란
systemd(system daemon)은 Unix 시스템 부팅 후 가장 먼저 생성된 후 다른 프로세스를 실행하는 init 역할을 하는 데몬이다. RedHat 에서 개발을 시작했고 RHEL/CentOS 와 Ubuntu 나 Arch 등 대부분의 리눅스 시스템에 공식적으로 채택되어 사용중이다.
systemd 는 PID 1번을 갖으며 부팅부터 서비스관리, 로그관리 등을 담당한다. 부팅 시 병렬로 실행되기 때문에 부팅속도 역시 빠르다.
부팅 시 필요한 작업을 systemd unit 으로 등록하여 사용할 수 있으며, 해당 파일들은 /etc/systemd/system 에 위치한다.
Good to know
service vs systemctl 차이
systemctl이 정식(현대) 명령어이고, service는 과거(init.d)와의 호환을 위한 래퍼(wrapper)이다.
systemd 환경에서 service nginx start 는 사실 systemctl start nginx.service 을 호출한다.
service 는 enable 을 지원하지 않는다.
systemctl 이 표준이다.
init.d 와 upstart
init.d → upstart → systemd 리눅스 init 시스템의 진화 과정이다.
init.d는 SysV init 기반의 스크립트형 init 시스템이고, upstart는 이벤트 기반으로 이를 개선한 과도기적 init 시스템이며, 현재 리눅스의 표준 init 시스템은 systemd이다.