这是我参与「第五届青训营」笔记创作活动的第五天
自动内存管理
自动内存管理(垃圾回收):由程序语言的运行时系统管理动态内存
自动内存管理的三个任务:
- 为新对象分配内存
- 找到存活对象
- 回收死亡对象的内存空间
相关概念
- Mutator:业务线程,分配新对象,修改对象指向关系
- Collector:GC线程,找到存活对象,回收死亡对象的内存空间
- Serial GC:只有一个Collector
- Parallel GC:支持多个Collertor同时回收
- Concurrent GC:Mutator和Collector同时执行
Serial GC 和 Parallel GC 会发生Stop The World 暂停业务线程,Concurrent GC 不会发生暂停业务线程,业务线程和GC线程会一起执行
GC算法评价指标
- 安全性
- 吞吐率
- 暂停时间
- 内存开销
追踪垃圾回收算法
会维护对象的树形结构
被回收的条件:指针指向关系不可达的对象
步骤:
-
标记根对象(如静态变量、全局变量、常量等)
-
标记可达对象(从根对象出发,指针指向关系可达的对象)
-
清理所有不可达对象
清理算法:
- Copy GC:将存活对象复制到另外的内存空间
- Mark-Sweep GC:将死亡对象标记为可分配
- Mark-compact GC:移动并整理存活对象
根据对象的生命周期可以选择不同的标记和回收策略
引用计数算法
每个对象都有一个与之关联的引用数目,当引用数目大于0时,表明该对象时存活的,不能被回收,反之,可以被回收
优点:这样的GC算法可以被平坦到程序的执行当中,可以实现不会发生Stop The World
缺点:
-
内存开销大:每个对象都需要额外的内存空间存储技术
-
维护引用数目的开销比较大,需要通过原子操作保证对象引用数目正确
-
很难处理环形数据结构——Weak Reference
-
回收内存时依然可能发生暂停(回收大对象的时候还是会引发暂停)
分代GC思想
很多对象的生命周期很短暂,在分配之后就没有再使用了。也有一些对象生命周期很长,不管回收多少次都任然存活。
针对这种情况,提出了分代假说:
给对象设置年龄(年龄随着GC的次数增长),不同年龄的对象存活在不同的内存空间:
- 年轻代:内存分配的区域,大多数对象的生命周期短暂,存活的对象很少,可以使用Copy GC
- 老年代:由年轻代反复存活的对象复制而来,对象趋向于一直活着,可以使用Mark-Sweep GC