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>)而非静态链接(<*>),可以显著减少内核初始化阶段需要扫描和注册的设备数量。模块化驱动的核心策略如下:

  1. 识别必须内置的驱动:根文件系统所在存储控制器(如 SD/MMC、NAND Flash 控制器)必须编译进内核,否则无法挂载根文件系统。
  2. 模块化非关键驱动:音频、视频、USB、网络 PHY 等外设驱动全部编译为模块,在用户空间按需加载。
  3. 使用 initramfs 预加载:将关键模块打包进 initramfs,在用户空间早期阶段加载,避免内核静态初始化开销。
  4. 延迟加载:对于启动阶段不需要的模块,推迟到系统启动完成后由 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 内核配置裁剪流程

下图展示了从基准配置到最终裁剪配置的完整工作流程:

内核配置裁剪工作流程 获取硬件平台基准配置 关闭所有非必需功能(网络/文件系统/驱动) 将非关键驱动改为模块(<M>) 启用尺寸优化选项(-Os / SLOB / 关闭调试) 编译测试并验证功能完整性 功能缺失时回退 建议:每次裁剪后使用 bootgraph 或 initcall_debug 测量启动时间变化,量化优化效果

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 生成一个接近最小需求的配置,然后在此基础上逐项微调。这样可以避免从零开始配置的繁琐工作。