静态编译和动态编译是两种编译的形式,静态编译简单来说就是全部编译完毕,编译器将代码直接编译成二进制码,链接器把静态库(.a)编译进去。而动态编译也叫延时编译,只将代码编译成中间码,就是将编译过程延迟到程序运行时进行。

相比较而言,两种编译各有优点,c++使用较多的是静态编译

1. 静态编译

原理

  • 编译器(如 GCC、Clang)将源代码(C/C++ 等)翻译为目标机器的二进制代码。
  • 链接器将目标代码与静态库(.a 文件)链接,生成完整可执行文件。
  • 所有符号解析和地址分配在编译时完成。

优点

  • 性能高效:运行时直接执行机器码,无编译开销,速度快。
  • 独立性强:可执行文件包含所有依赖,运行时无需额外库(除系统级动态库)。
  • 优化充分:编译器可在编译时进行全局优化(如内联、死代码消除)。
  • 可预测性:资源需求固定,适合嵌入式系统。

缺点

  • 文件较大:因包含所有依赖,可执行文件体积大。
  • 不可动态更新:修改代码需重新编译和部署。
  • 兼容性问题:针对特定平台编译,跨平台需重新编译。

应用场景

  • 嵌入式系统:资源受限,需独立运行(如微控制器程序)。
  • 高性能应用:游戏引擎、操作系统内核(如 Linux 内核部分)。
  • 静态链接程序:不依赖外部库的工具。

2. 动态编译

原理

  • 源代码先编译为中间表示(如 Java 字节码、.NET IL 代码)。
  • 运行时,JIT 编译器(如 Java 的 HotSpot、JavaScript 的 V8 引擎)将中间代码动态编译为机器码。
  • 编译可能只针对热点代码(频繁执行的部分),结合解释执行。

优点

  • 灵活性高:运行时可根据硬件和上下文优化代码(如 CPU 特性)。
  • 跨平台:中间代码与平台无关,JIT 编译适配目标机器。
  • 动态优化:根据运行时数据(如分支预测)优化性能。
  • 更新便捷:无需重新编译整个程序,适合动态语言。

缺点

  • 启动延迟:运行时编译增加启动时间。
  • 资源占用:编译过程消耗 CPU 和内存。
  • 复杂性高:JIT 编译器实现复杂,调试困难。

应用场景

  • 虚拟机:Java(JVM)、.NET(CLR)运行时环境。
  • 动态语言:JavaScript(V8 引擎)、Python(PyPy 的 JIT)。
  • 性能敏感应用:结合运行时信息优化的场景(如数据库查询)。

3. 对比表格

特性 静态编译 动态编译
编译时机 运行前 运行时
输出 机器码(可执行文件) 中间代码 + 运行时机器码
性能 启动快,运行高效 启动慢,运行可优化
文件大小 较大(含依赖) 较小(中间代码)
跨平台 需为各平台单独编译 中间代码跨平台,运行时适配
优化 编译时全局优化 运行时动态优化
典型语言 C, C++, Rust Java, JavaScript, Python

顺便说一下,静态链接与动态链接

静态链接与动态链接

静态链接在静态编译上说到了,是将.a这种静态库直接编译进去,而动态编译只是在运行时才调用.so库

对比表格

特性 静态链接 动态链接
链接时机 编译时 运行时
可执行文件大小 较大(包含库代码) 较小(仅符号引用)
内存使用 每个程序复制库代码,占用高 共享库代码,节省内存
启动速度 快,无加载开销 慢,需加载和解析符号
部署 简单,自包含 需确保共享库存在
更新 需重新编译整个程序 仅更新共享库
灵活性 不支持插件或动态加载 支持插件和模块化设计
典型库文件 .a (Linux), .lib (Windows) .so (Linux), .dll (Windows)