语言运行时
复习
- 动态链接与装载:运行时才把库接上
- 程序在内存里的样子:代码区、数据区、栈和堆
- 编译器:把程序翻译成可运行的形式
TL;DR
- 语言运行时是高级语言背后的一组隐藏服务
- 它负责内存管理、对象模型、异常、并发等
- 有些工作由编译器直接生成代码,有些由运行时库提供
- 语言越好用,往往运行时越“重”
正文
一路走到这里,编译器似乎已经把所有事都做完了:读懂、优化、生成机器码、链接。可高级语言用起来那么“舒服”——你不用手动管理内存、不用关心对象在哪、还能随手抛个异常——这些便利,总得有人买单。
买单的,就是语言运行时(language runtime)。
高级语言的“甜”是谁给的
想一想,哪些事你从没亲手做过:
- 申请和释放对象的内存
- 检查数组越界
- 抛出和捕获异常
- 记录每个对象的类型
- 支持多线程
这些都不是“凭空”发生的。它们要么由编译器在生成的代码里插入检查与调用,要么由一组运行时库在程序运行时提供服务。这整套支撑,就是语言运行时。
编译器和运行时怎么分工
两者的分工大致是这样:
- 编译器:能静态确定的,就直接生成代码(比如类型检查、部分内存布局)
- 运行时:需要“运行时才知道”的,交给运行时库(比如动态分配、垃圾回收、动态派发、异常展开)
两者配合,才让高级语言既好用又能跑。
越“甜”,越“重”
这里有一条很有意思的规律:语言提供的便利越多,运行时往往越庞大、越复杂。
比如带自动垃圾回收的语言,需要一整套垃圾回收器;支持反射、动态派发的,要维护类型信息;有异常机制的,要维护异常处理数据。相比之下,贴近底层的语言,运行时可能非常小。
这又回到了那个熟悉的味道:没有免费的便利。 语言帮你做的事越多,背后替你干活的运行时就越重。接下来几章,就看几项典型的运行时服务。
思考题 1
语言运行时大致负责哪些工作?
思考题 2
为什么说“语言越好用,运行时往往越重”?
小结
知识点
- 语言运行时提供高级语言背后的隐藏服务
- 职责包括内存管理、对象模型、异常、并发等
- 编译器生成部分代码,运行时库提供其余服务
- 语言特性越丰富,运行时通常越大
参考资料
- Wikipedia(zh):运行时系统:程序运行期间提供支持的系统
- Wikipedia(zh):垃圾回收:运行时自动管理内存的机制
思考题答案(仅供参考)
思考题 1
它负责程序运行时需要的各种支持,例如内存分配与垃圾回收、对象与类型信息的维护、异常处理、动态方法派发、线程与并发支持等。部分是编译器插入的代码,部分是运行时库提供的服务。
思考题 2
因为语言提供的每项便利通常都需要运行时的支撑:自动内存管理要有垃圾回收器,异常机制要有异常处理数据,动态派发要有类型信息。便利越多,需要的运行时服务就越多,运行时也就越大越复杂。
协议
本作品采用知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议进行许可。
封面图
设计师 | 南国微雪