什么是垃圾
程序已经没有引用的对象,包括栈、堆。栈上的垃圾在方法执行完成后就会回收。垃圾回收器讨论的是堆上的垃圾回收
垃圾定位算法
- 根可达算法,目前流行。从根开始,遍历对象和对象的属性,找出可以触达的对象。遍历完之后不可触达的对象可认定为垃圾
GCRoot:线程栈变量、静态变量、常量池、本地方法栈中JNI指针 - 引用计数器(已过时):使用计数器来记录对象引用次数,如果计数器为零,则认为没有引用,可认定为垃圾。但是不能解决循环引用问题
- 遗留问题:弱引用如何解决。回答:弱引用,如果在对象回收时调用对象的finalize方法后没有编程强引用,则回收。另外需要说明的是,finalize方法只会调用一次
垃圾回收算法
- Marking Sweep 标记清除
- Coping 拷贝
- Marking Compact 标记压缩
内存分配方式
- 指针碰撞,对应拷贝回收算法和标记整理
- 空闲列表,对应标记清除
垃圾回收器
分代模型
- 新生代:ParNew、Serial、Parallel Scavenge
- 老年代:CMS、Serial Old、ParOld
解释:图中分代模型连接起来的回收器可以相互配合使用,没有连接的不能配合使用。
特别说明:【CMS】与【Serial Old】的连接线,意思是【CMS】产生大量碎片,使大对象不能分配内存时,降级为【Serial Old】。如果内存很大,单线程回收很耗时
现状:目前jdk1.8默认使用ps/po(【Parallel Scavenge】+【ParOld】)组合,也可使用G1。不建议使用CMS因为会降级为【Serial Old】
分区模型
G1、ZGC、Shenandoah、Epsilon
- Epsilon:不进行回收的垃圾回收器,用于分析内存分配流程和debug
其它介绍后续分享
对象在内存中的生命周期
- 如果是基本数据类型,直接在栈分配空间
- TLAB(Thread Local Allocation Buffer),线程本地内存缓冲。分配内存是同步的,会存在多线程资源竞争,缓冲可以减少竞争压力
特别说明:
- 逃逸:如果直接在栈上分配空间,则需要保证该对象没有【逃逸】(被别的线程引用),否则产生野指针,引起空指针
- 标量替换:如果一个对象的成员变量都是基本类型,则可以使用基本类型组合替代该对象
END