这是青训营笔记的第二篇文章。
自动内存管理
自动内存管理又叫做垃圾回收,是语言原生运行时系统的重要组件,用于管理动态内存。 相关概念:
- 死亡对象 在内存中已经没有任何引用的对象,也就是说,程序不再需要使用这些对象的数据或功能。
- 存活对象 内存中仍然被引用的对象,也就是说,程序还需要使用这些对象的数据或功能。
- Mutator 业务线程,指用户程序
- Allocator 分配器,用于分配新对象,修改对象指向关系
- Collector GC线程,找到存活对象,回收死亡对象的内存空间
好处: 1. 避免程序员手动管理内存,灵程序员能够专注业务逻辑(可以直接调用语义约定来实现逻辑而不考虑实现细节) 2. 保证内存使用的正确与安全(典型问题:重复释放、释放后调用) 基础任务: 3. 为对象分配空间 4. 识别并标记存活对象 5. 回收死亡对象的内存空间
自动内存管理技术
主流技术分为GC和引用计数两种。
追踪垃圾回收
根据对象的生命周期,使用不同的标记和清理策略 关键活动:
- 标记根对象(静态变量、全局变量、常量、线程栈等)
- 标记可达对象
- 求指针指向关系的传递闭包1:从根对象出发,寻找所有可达对象
- 清理不可达对象内存空间
- Copying GC
- 将存活对象=复制到其他内存空间,整体释放
- Mark-sweep GC
- 将死亡对象空间标记为可分配
- Mark-compact GC
- 移动并整理(常常是原地)存活对象
- Copying GC
分代GC
分代假说:most objects die young 对象的年龄就是对象经历的GC次数 分代GC针对年轻和老年的对象,制定不同的GC策略
- 年轻代
- GC吞吐率较高
- 采用常规对象分配
- 由于存活对象少,采用Copying GC
- 老年代
- 独享趋向于一直存活,反复复制开销较大
- 采用Mark-sweep GC避免复制
引用计数
原生记录对象的被引用次数,当且仅当被引用数大于0,对象存活。 但引用计数无法释放环形数据结构(循环依赖),且引用计数需要通过原子操作保证对引用计数操作的原子性与可见性,导致维护的开销较大。
Footnotes
-
传递闭包是在集合 X 上求包含关系 R 的最小传递关系。从关系图的角度来说,就是如果原关系图上有 i 到 j 的路径,则其传递闭包的关系图上就应有从 i 到 j 的边。 ↩