메모리가 작은 시스템을 위한 커널 경량화 (2) — initrd 사용에 따른 영향

지난 편에서는 initrd 없이 root=/dev/vda로 직접 부팅하는 구성으로 defconfig 커널의 베이스라인을 측정했다. 하지만 실제 임베디드/컨테이너 이미지에서는 initrd(정확히는 initramfs)를 쓰는 구성도 흔하다 — 루트 파일시스템 드라이버를 모듈로 빼두고 initramfs에서 필요한 것만 로드하는 유연성 때문이다. 문제는 이 유연성이 공짜가 아니라는 점이다. 이 글에서는 같은 커널을 initrd 구성으로 다시 부팅해 이미지 크기·RAM 사용량·부팅 시간을 지난 편 베이스라인과 직접 비교한다.

이 시리즈의 다른 글

테스트 환경

커널 바이너리(bzImage)는 지난 편과 완전히 동일하다. rootfs 구성만 바뀐다 — 지난 편은 ext4 디스크 이미지를 virtio-blk로 직접 마운트했고, 이번엔 busybox만 담은 cpio를 initramfs로 커널에 함께 로드한다.

항목지난 편 (initrd 없음)이번 편 (initrd 사용)
커널동일한 bzImage (defconfig)동일한 bzImage (defconfig)
rootfsext4 64MB, -drive ... root=/dev/vdabusybox cpio.gz, -initrd
필수 built-in 옵션CONFIG_VIRTIO_BLK, CONFIG_EXT4_FS없음 (모듈로도 가능)

initrd로 부팅하기

init 스크립트는 지난 편과 동일하게 proc/sysfs를 마운트하고 측정값을 출력한 뒤 종료한다. 이번엔 -drive 없이 -initrd만 넘긴다.

qemu-system-x86_64 \
  -kernel arch/x86/boot/bzImage \
  -initrd initramfs-min.cpio.gz \
  -append "console=ttyS0 quiet" \
  -m 1024M \
  -nographic \
  -no-reboot
===== free -m =====
              total        used        free      shared  buff/cache   available
Mem:            969          19         947           2           3         938
Swap:             0           0           0
===== /proc/meminfo (head) =====
MemTotal:         992240 kB
MemFree:          970144 kB
MemAvailable:     960780 kB
Buffers:               0 kB
Cached:             2052 kB
===== slab total =====
Slab:               6752 kB
SReclaimable:        784 kB
SUnreclaim:         5968 kB
===== boot done =====
[    3.856575] reboot: Power down

비교 결과

항목initrd 없음initrd 사용차이
부팅 페이로드 (부트로더가 사전 로드)bzImage 14.8MB (rootfs는 디스크에서 필요 시 읽음)bzImage 14.8MB + initramfs 1.06MB = 15.9MB (전부 사전 로드)+1.06MB
부팅 직후 used13 MB19 MB+6 MB
shared (ramfs 상주분)0 MB2 MB+2 MB
buff/cache3 MB (Buffers 108kB 포함, 블록 I/O 캐시)3 MB (Buffers 0kB, 블록 디바이스 자체가 없음)
Slab 총합6.7 MB6.8 MB+0.1 MB
커널 타임스탬프 (userspace 도달)5.37초3.86초-1.51초

부팅 시간은 오히려 initrd 쪽이 더 짧았다. virtio-blk PCI 프로브와 ext4 마운트에 걸리는 시간이 통째로 빠지기 때문이다. 대신 RAM은 initrd 쪽이 6MB 더 쓴다 — initramfs 콘텐츠가 ramfs로 마운트되기 때문에 페이지가 회수(reclaim) 대상이 아니라 그대로 상주한다.

주의사항

  • initramfs는 ramfs 위에 풀리기 때문에 switch_root로 진짜 rootfs로 넘어가기 전까지 그 콘텐츠가 RAM에서 회수되지 않는다. 이 글은 initramfs를 최종 rootfs로 그대로 쓰는 경우만 측정했고, “initramfs에 모듈만 담아 부팅한 뒤 실제 rootfs로 switch_root하고 initramfs 메모리를 반납”하는 2단계 구성은 별도로 검증하지 않았다 — 이 경우 순간적으로는 initramfs+실제 rootfs 드라이버가 동시에 메모리에 있어야 하므로 위 표의 +6MB보다 일시적으로 더 커질 수 있다.
  • 부팅 시간 차이(-1.51초)는 QEMU의 virtio-blk 프로브 오버헤드에 크게 좌우된 결과다. 실기기의 NVMe/eMMC처럼 훨씬 빠른 스토리지에서는 이 격차가 줄어들 수 있다.
  • initrd 구성에서는 지난 편에서 다룬 “블록 드라이버·파일시스템이 반드시 built-in이어야 한다”는 제약이 사라진다. 필요한 드라이버를 모듈로 두고 initramfs 안에 .komodprobe 스크립트를 넣어두면 되기 때문인데, 이건 곧 vmlinux 자체 크기를 줄이는 데는 initrd 쪽이 유리할 수 있다는 뜻이다 — 다음 편에서 Kconfig 옵션을 정리할 때 이 트레이드오프를 다시 참고한다.

마무리

같은 커널로 두 가지 부팅 방식을 비교한 결과, initrd는 부팅이 더 빠른 대신 RAM을 더 쓰고, initrd 없이 직접 마운트하는 쪽은 RAM은 아끼지만 필수 드라이버를 전부 built-in으로 강제한다는 트레이드오프가 실측으로 확인됐다. 메모리가 빠듯한 시스템이라면 이 6MB(전체 RAM의 0.6% 수준이지만 128MB급 초저사양 보드에서는 5% 가까이 된다) 차이가 실제 선택 기준이 될 수 있다. 다음 편에서는 menuconfig/localmodconfig로 두 구성 모두에 공통으로 적용 가능한 Kconfig 옵션들을 정리하며 이미지 크기를 줄인다.

참고

답글 남기기