Learn && Live
虚度年华浮萍于世,勤学善思至死不渝
前言
Hey,欢迎阅读Connor学JVM系列,这个系列记录了我的JVM基础知识学习、复盘过程,欢迎各位大佬阅读斧正!原创不易,转载请注明出处:http://t.csdn.cn/bqtSk,话不多说我们马上开始!
1.分代收集理论
弱分代假说
绝大多数对象都是朝生夕灭的
强分代假说
Java堆划分出不同的区域,将回收对象依据年龄分配到不同的区域之中存储,一般分为新生代和老生代,注意这里只关注划分区域,没有涉及“年龄增长”的概念
跨代引用
当出现跨代引用时,即新生代的对象与老年代的对象之间存在引用,由于老年代对象难以消亡,该引用会使新生代对象一起存活,进而在之后晋升到老年代中,这种跨代引用也随即消除了
2.什么是 STW(Stop The World)
垃圾回收首先是要经过标记的,对象被标记后就会根据不同的区域采用不同的收集方法。垃圾回收并不会阻塞我们程序的线程,他是与当前程序并发执行的。所以问题就出在这里,当GC线程标记好了一个对象的时候,此时我们程序的线程又将该对象重新加入了“关系网”中,当执行二次标记的时候,该对象也没有重写finalize()方法,因此回收的时候就会回收这个不该回收的对象。
虚拟机的解决方法就是在一些特定指令位置设置一些“安全点”,当程序运行到这些“安全点”的时候就会暂停所有当前运行的线程(Stop The World 所以叫STW),暂停后再找到GC Roots进行关系的组建,进而执行标记和清除。
这些特定的指令(安全点)位置主要在:
(1)循环的末尾
(2)方法临返回前 / 调用方法的call指令后
(3)可能抛异常的位置
停顿类型就是STW,至于有GC和Full GC之分,主要是Full GC时STW的时间相对GC来说时间很长,因为Full GC针对整个堆以及永久代的,因此整个GC的范围大大增加;还有就是他的回收算法就是“标记–清除–整理”,这里也会损耗一定的时间。所以我们在优化JVM的时候,减少Full GC的次数也是经常用到的办法。
3.标记 - 清除算法 Mark - Sweep
首先标记所有需要回收的对象,再统一回收掉所有被标记的对象
或者标记存活的对象,回收未标记的对象
主要缺点:
- 执行效率不稳定。当堆中存在大量需要回收的对象,则需要大量的标记和清除操作,导致效率降低
- 内存空间碎片化问题。标记清楚后会产生大量不连续的内存空间——内存碎片,无法保证大对象的分配
4.标记 - 复制算法 Copying - 优先采用的针对新生代的回收算法
半区复制
(1)将可用内存按容量划分为等大的两块,每次只使用其中一块
(2)一块内存用完后将还存活着的对象复制到另一块上,再将已使用完的这一块全部回收
(3)优点是当多数对象需要回收时仅需复制少部分对象,且针对整个半区复制,不用考虑有空间碎片的情况
(3)缺陷是将可用内存缩小了一半,空间浪费大,且当大多数对象存活时会产生大量的复制开销
Appel式回收
针对上述缺陷做了如下设计
(1)把新生代分为一块较大的Eden空间和两块较小的Survivor空间,每次分配只使用Eden和一块Survivor
(2)发生垃圾回收时,将Eden和Survivor中存活的对象复制到另一块Survivor中,然后清理Eden和用过的Survivor
(3)如果另外一块Survivor空间不足以存放存活的对象,则会通过分配担保机制直接进入老年代
HotSpot虚拟机默认Eden : Survivor = 8 : 1
5.标记 - 整理算法 Mark - Compact - 优先采用的针对老年代的回收算法
(1)标记过程与标记 - 清除算法一致
(2)让所有存活的对象都向内存空间一端移动,然后清除边界以外的内存