3. 内核配置裁剪:关闭不必要的内核功能、模块化驱动、使用内核尺寸优化选项
内核配置裁剪是启动时间优化中性价比最高的手段之一。一个通用发行版内核包含了大量嵌入式系统不需要的功能、驱动和调试选项,这些代码在内核初始化阶段会被逐一扫描、注册和初始化,直接拖慢启动流程。通过精确裁剪,通常可以减少 30%–50% 的内核镜像尺寸,并将启动时间缩短数百毫秒甚至数秒。
3.1 裁剪的核心原则
在进行内核配置裁剪时,应遵循以下三条基本原则:
- 最小化原则:只保留系统启动和核心功能所必需的选项,其余一律关闭。
- 模块化原则:对于不能完全关闭但非必需的功能,编译为可加载模块(<M>),避免其在内核初始化阶段被静态链接和初始化。
- 尺寸优化原则:启用内核提供的尺寸优化编译选项,减小内核镜像的二进制体积。
实战提示:建议在项目初期就建立一份
minimal_defconfig,基于硬件平台的最小需求进行配置,而不是在通用配置上做减法。这样可以避免遗漏隐藏的依赖选项。
3.2 可关闭的典型功能类别
下表列出了嵌入式 Linux 系统中通常可以安全关闭的功能类别及其对启动时间的影响程度:
| 功能类别 | 典型配置选项 | 启动时间影响 | 裁剪建议 |
|---|---|---|---|
| 网络协议栈 | CONFIG_INET, CONFIG_IPV6 |
中 | 若设备无需网络,可完全关闭;否则只保留 IPv4 |
| 文件系统支持 | CONFIG_EXT4_FS, CONFIG_BTRFS_FS |
高 | 只保留根文件系统使用的类型(如 squashfs、ubifs) |
| 设备驱动 | CONFIG_SOUND, CONFIG_USB |
高 | 关闭所有未使用的硬件驱动,或编译为模块 |
| 调试与追踪 | CONFIG_DEBUG_KERNEL, CONFIG_FTRACE |
中 | 生产环境必须全部关闭 |
| 电源管理 | CONFIG_PM, CONFIG_CPU_IDLE |
低 | 若设备无需休眠,可关闭 |
| 安全模块 | CONFIG_SECURITY, CONFIG_SELINUX |
中 | 嵌入式环境通常可关闭 |
| 虚拟化 | CONFIG_KVM, CONFIG_VIRTIO |
低 | 非虚拟化场景直接关闭 |
3.3 模块化驱动的策略
将驱动编译为可加载模块(<M>)而非静态链接(<*>),可以显著减少内核初始化阶段需要扫描和注册的设备数量。模块化驱动的核心策略如下:
- 识别必须内置的驱动:根文件系统所在存储控制器(如 SD/MMC、NAND Flash 控制器)必须编译进内核,否则无法挂载根文件系统。
- 模块化非关键驱动:音频、视频、USB、网络 PHY 等外设驱动全部编译为模块,在用户空间按需加载。
- 使用 initramfs 预加载:将关键模块打包进 initramfs,在用户空间早期阶段加载,避免内核静态初始化开销。
- 延迟加载:对于启动阶段不需要的模块,推迟到系统启动完成后由 udev 或 modprobe 按需加载。
性能数据:在某 ARM Cortex-A7 平台上,将 12 个非关键驱动从静态编译改为模块化后,内核解压和初始化时间从 1.2s 降至 0.7s,节省约 42%。
3.4 内核尺寸优化选项
Linux 内核提供了多个编译时尺寸优化选项,可以在 General setup 和 Kernel hacking 菜单中找到:
| 配置选项 | 说明 | 典型节省 |
|---|---|---|
CONFIG_CC_OPTIMIZE_FOR_SIZE |
使用 -Os 优化级别,优先减小代码尺寸 |
10%–20% |
CONFIG_KERNEL_UNCOMPRESSED |
关闭内核压缩,减少解压时间(适用于大 RAM 设备) | 解压时间归零 |
CONFIG_EMBEDDED |
启用嵌入式专用优化,允许更细粒度的裁剪 | 5%–15% |
CONFIG_SLOB |
使用 SLOB 内存分配器替代 SLUB,减少内存占用 | 内存占用减少 10% |
CONFIG_PRINTK |
关闭内核日志输出,减少 I/O 开销 | 启动时间减少 5%–10% |
CONFIG_DEBUG_INFO |
关闭调试符号信息 | 镜像尺寸减少 50%+ |
3.5 内核配置裁剪流程
下图展示了从基准配置到最终裁剪配置的完整工作流程:
3.6 实战案例:基于 ARM 平台的裁剪清单
以下是一个基于 ARM Cortex-A7 平台的典型裁剪清单,展示了从默认配置到最小配置的关键变更:
# 关闭网络协议栈(设备无需联网)
# CONFIG_NET is not set
# 关闭 IPv6
# CONFIG_IPV6 is not set
# 只保留 squashfs 和 ubifs 文件系统
CONFIG_SQUASHFS=y
CONFIG_UBIFS_FS=y
# CONFIG_EXT4_FS is not set
# CONFIG_BTRFS_FS is not set
# CONFIG_F2FS_FS is not set
# 关闭音频子系统
# CONFIG_SOUND is not set
# 关闭 USB 子系统(设备无 USB 外设)
# CONFIG_USB is not set
# 关闭所有调试选项
# CONFIG_DEBUG_KERNEL is not set
# CONFIG_FTRACE is not set
# CONFIG_PRINTK is not set
# 启用尺寸优化
CONFIG_CC_OPTIMIZE_FOR_SIZE=y
CONFIG_SLOB=y
# 关闭安全模块
# CONFIG_SECURITY is not set
# CONFIG_SELINUX is not set
注意事项:裁剪前务必确认硬件平台的关键依赖。例如,某些 SoC 的 DMA 引擎驱动可能被多个外设共享,直接关闭会导致系统崩溃。建议在裁剪后执行完整的硬件功能测试,包括网络、存储、外设接口等。
3.7 裁剪效果验证
完成配置裁剪后,建议通过以下指标量化优化效果:
- 内核镜像尺寸:对比裁剪前后的
vmlinux或zImage大小。 - 内核解压时间:通过串口日志或 bootgraph 测量从 bootloader 跳转到内核入口到内核开始初始化的时间。
- initcall 执行时间:使用
initcall_debug内核参数,统计每个初始化函数的执行耗时。 - 总启动时间:从上电到用户空间第一个进程启动的完整时间。
下表展示了某实际项目中的裁剪效果数据:
| 指标 | 裁剪前 | 裁剪后 | 优化幅度 |
|---|---|---|---|
| 内核镜像尺寸 (zImage) | 4.2 MB | 1.8 MB | 57% |
| 内核解压时间 | 320 ms | 140 ms | 56% |
| initcall 总耗时 | 680 ms | 310 ms | 54% |
| 总启动时间 (上电 → shell) | 3.2 s | 1.9 s | 41% |
3.8 自动化裁剪工具
对于大型项目,手动逐项裁剪效率较低。推荐使用以下工具辅助裁剪:
- localmodconfig:基于当前系统已加载的模块生成最小配置,快速剔除未使用的驱动。
- tinyconfig:生成一个极小的内核配置,仅包含最基本的功能,适合从零开始构建。
- kconfig-hardened-check:检查配置中是否存在不必要的安全或调试选项。
# 使用 localmodconfig 快速生成最小配置
make localmodconfig
# 基于 tinyconfig 开始构建
make tinyconfig
make menuconfig # 按需添加必要功能
效率技巧:在开发阶段,可以先使用
localmodconfig 生成一个接近最小需求的配置,然后在此基础上逐项微调。这样可以避免从零开始配置的繁琐工作。