HNU 编译系统 第一次作业
注:由于前两题涉及的内容没怎么接触过,故大部分内容由AI完成
题目1
1. JDK 与 JRE 的主要区别(从编译功能角度)
- JDK (Java Development Kit)
- 提供 编译功能(
javac
编译器),能把.java
源文件编译为.class
字节码文件。 - 同时包含 JRE,因此既能编译,也能运行 Java 程序。
- 提供 编译功能(
- JRE (Java Runtime Environment)
- 只提供 运行环境,不包含编译器。
- 可以运行
.class
文件,但无法直接编译.java
文件。
2. 如果只有 .java
源文件
- 必须安装:JDK
- 理由:
.java
文件是源代码,运行之前需要用 JDK 里的javac
编译器编译成.class
字节码,然后才能运行。
3. 如果只有 .class
字节码文件
- 必须安装:JRE(JDK 也可以,因为包含 JRE)
- 理由:
.class
文件已经是编译好的字节码,可以直接由 JVM 执行,不需要编译器。只要有 JRE 就能运行。
4. C++ / Golang / Java 的编译开销与运行性能取舍
1. C++
- 编译开销
- C++ 需要把源代码(
.cpp
)编译为平台相关的二进制可执行文件。 - 编译过程复杂:涉及词法分析、语法分析、语义检查、优化(O1~O3)、链接(可能还需要处理模板、头文件等)。
- 因此,编译耗时较长,尤其在大型项目中。
- C++ 需要把源代码(
- 运行性能
- 编译生成的是直接运行在操作系统上的 机器码,不依赖虚拟机。
- 性能极高,接近硬件极限,适合对性能要求苛刻的领域(游戏引擎、操作系统内核、高频交易系统等)。
- 特点总结
- 取舍:牺牲较长的编译时间,换取几乎最佳的运行性能。
2. Golang (Go)
- 编译开销
- Go 采用更简单的语法和依赖管理方式(没有复杂的头文件和宏展开),编译过程更轻量。
- 编译结果是一个静态链接的可执行文件(包含所需库和依赖)。
- 相比 C++,编译速度非常快,即使在中大型项目中也能迅速完成。
- 运行性能
- 程序直接运行在操作系统上,不依赖虚拟机。
- 性能通常略低于 C++,主要原因是 Go 更注重开发效率(比如自动垃圾回收 GC、内存安全),这些机制会带来一定开销。
- 但 Go 的性能已经足够支撑大部分高并发服务场景。
- 特点总结
- 取舍:用更快的编译速度和更高的开发效率,换取相较于 C++ 略低的运行性能。
3. Java
- 编译开销
- Java 源代码(
.java
)首先被编译为 字节码文件(.class
),这一步非常快。 - 字节码与平台无关,可以在任何有 JVM 的环境中运行。
- 因此,编译速度最快(相比 C++、Go),适合快速开发和跨平台分发。
- Java 源代码(
- 运行性能
- 程序运行时需要 JVM 解释执行字节码。
- 为提升性能,现代 JVM 使用 JIT(即时编译器),在程序运行过程中把热点代码编译为机器码,并进行运行时优化(如内联、逃逸分析等)。
- 运行性能在长期执行的服务中可以接近 C++,但启动时性能(冷启动)会略逊。
- 特点总结
- 取舍:牺牲部分运行时性能,换取快速的开发编译周期和极强的跨平台能力。
题目2
1. PyTorch 的编译流程
在 PyTorch 里,我们写代码的时候其实是 Python 前端,底层调用 C++/CUDA 的算子。它的“编译”大概分几个步骤:
- 默认是动态图模式,写一句运行一句。
- 如果要优化,可以用 JIT(TorchScript),把模型转成静态图。
- 静态图可以做一些优化,比如算子合并、常量折叠。
- 最后会映射到 CPU 或 GPU,调用高性能库(像 cuDNN、MKL),并针对硬件做优化。
2. 和传统编译的相同点
- 都会有一个中间表示(IR)。
- 都会做优化,目的都是让程序运行得更快。
- 都要考虑跨平台运行。
3. 和传统编译的不同点
- 传统编译器最后得到的是机器码;PyTorch 更多是得到“优化后的计算图”和“库调用”。
- 传统编译器主要在指令层面优化;PyTorch 更关注算子优化、内存和并行计算。
- 传统编译器是先编译再运行;PyTorch 有动态图,也有运行时 JIT,可以边运行边优化。