jvm中垃圾回收算法
垃圾回收算法
如何判断是否是垃圾:
沿着GC Root找,如果没有被GCRoot直接引用,则会判定为垃圾
- 标记清除发
- 分代整理
- 复制
1.1 标记清除算法
先标记后清除
优点:速度快,垃圾回收速度快
缺点:空间不连续,容易产生内存碎片,会导致内存溢出
1.2标记整理算法
优点:不会产生内存碎片
缺点:由于需要移动对象,如果其他对象引用了,则需要改变引用地址,涉及到内存的区块的拷贝移动,速度较慢
1.3 复制算法
优点:不会产生内存碎片
缺点:会占用双倍的内存空间
- 总结
在JVM中,面对不同的情况会采用上面不同的算法实现垃圾回收
2.1 JVM中垃圾回收机制
分代的垃圾回收机制
新生代:用完了可以丢弃的对象
老年代:长时间使用的对象
- 新生代中可以分为两大块区域:Eden区和两个Survivor(幸存区)
疑问1:为什么要存在Survivor - 如果没有Survivor,Eden区每进行一次Minor GC,存活的对象就会被送到老年代。老年代很快被填满,触发Major GC(因为Major GC一般伴随着Minor GC,也可以看做触发了Full GC)。老年代的内存空间远大于新生代,进行一次Full GC消耗的时间比Minor GC长得多。
疑问2 :为什么要有两个Survivor - 设置两个Survivor区最大的好处就是解决了碎片化
2.1.1 垃圾回收机制过程
1.3:在将幸存的对象放进幸存区时,同时执行将幸存对象的寿命+1操作
1.8:当老年代的内存不足,会触发FullGc
2.2.2 总结
- new的对象首先会被分配到Eden区域
- 新生代空间不足时,触发Minor gc,将Eden和From中存活的对象使用copy算法复制到to中,存活的对象的年龄+1,并且交换from和to的位置。交换之前清除垃圾
- minor gc执行时会依法stop the word。暂停其他用户的线程,只存在垃圾回收线程,等垃圾回收结束,用户线程才会恢复运行,STW时间短。
- 当对象寿命超过阈值时,就会晋升至老年代,寿命阈值最大是15次(会保存对象的头中,存寿命的地方是4bit)。
- 当老年代空间不足,会先尝试触发minor gc,如果之后空间扔不足,会触发Full gc。也会触发stop the word。只不过STW的时间更长
- 为什么老年代的回收算法教程
* 新生代采用的复制算法, 老年代,存活对象比较多,清除起来比较慢
* 采用的算法是标记+清除或者标记+标记+整理
- 为什么老年代的回收算法教程
2.3 GC分析
2.4 大对象导致OutOfMemory
新生代无法存下,直接晋升老年代
当老年代也无法放下时,会报OutOfMemory
2.5 垃圾回收器
- 串行的垃圾回收器
* 底层是单线程垃圾回收器,
* 使用场景:堆内存较小,适合个人电脑 - 吞吐量优先
* 多线程
* 对内存较大,多核CPU支持
* 让单位时间内,STW的时间最短 - 响应时间优先
- 多线程
- 对内存较大,多核CPU支持
- 尽可能让单次STW(暂停其他线程)的时间最短;
吞吐量:垃圾回收时间占程序运行时间的占比,占比越低,吞吐量越高
2.5.1 串行垃圾回收器
- 开启的语句:-XX:UseSerialGC =Serial +SerialOld
2.5.2 吞吐量优先的垃圾回收器
目标1:调整吞吐量,调整垃圾回收和总时间的占比。1/1+ratio
eg:默认ratio=99,所以占比为0.01:说明垃圾回收时间不能超过总时间的0.01,如果工作100分钟,垃圾回收时间只能允许 1分 钟
目标2:最大暂停毫秒数,最大致为200ms。
2.5.3 响应时间优先垃圾回收器
2.6 Garbage First(G1垃圾回收器)
JDK9中默认的垃圾回收机制,取代 了CMS
2.6.1 G1垃圾回收阶段
- Young Collection(新生代)
- Young Collection +CM(新生代的垃圾回收和标记阶段)
- Young Collection 夸代引用
- Remark (重新标记)
以下为:并发标记时的状态
8)JDK 8u20字符串去重
9)JDK8u40并发标记类卸载
只会对自定义加载类执行卸载,JDK的类加载器不会被类卸载,会始终存在
10)JDK8u60 回收巨型对象区