JAVA虚拟机(五)垃圾收集器与对象分配和回收策略

可达性分析算法的效率
可达性分析中从GC Roots节点找引用链,可作为GC Roots的节点主要在全局性的引用(常量或类静态属性)与执行上下文(栈帧中的本地变量表),如果要逐个检查,必然会消耗很多时间。
另外,可达性分析对执行时间的敏感还体现在GC停顿上,因为这项工作必须在一个能确保一致性的快照中进行(Stop the world)。
目前的主流虚拟机不会一个不漏的检查完所有执行上下文和全局的引用位置,虚拟机有办法知道哪些地方存放着对象引用。

垃圾收集器
垃圾收集算法是内存回收的方法论,垃圾回收器就是内存回收的具体实现。
HotSpot虚拟机的收集器目前主要有:
新生代:Serial,ParNew,Parallel Seavenge
老年代:CMS , Serial Old, Parallel Old
两者兼顾:G1
Serial 只能使用一个CPU或者一条收集线程去完成垃圾收集工作,而且此时必须停掉其他所有的工作线程。特点是简单高效。
ParNew收集器其实就是Serial收集器的多线程版本,收集算法,Stop The World,对象分配规则,回收策略都和Serial完全一样。ParNew的优势在于多CPU的利用。
Parallel Scavenge收集器时一个新生代收集器,使用复制算法,也是并行的多线程收集器。与其他收集器不同的是,他并不关注垃圾收集时用户线程的停顿时间,更注重于吞吐量。
Serial Old是Serial的收集器的老年代版本,也是一个单线程收集器,使用标记整理算法。
Parallel Old是PS的老年代版本,使用多线程和标记整理算法。与PS组成了一个吞吐量组合。
CMS收集器是一种以获取最短回收停顿时间为目标的收集器,适用于B/S应用或者系统服务端,注重响应速度。基于标记清除算法。并发收集,低停顿,对CPU的资源非常敏感。
G1是一款面向服务端的应用垃圾收集器,能充分利用多CPU,多核的硬件优势来缩短Stop The World的时间。也是采用分代收集算法。为了能够不产生空间碎片,G1的算法是基于标记整理算法的。

GC日志的理解
以下面这个典型的GC日志为例子:
在这里插入图片描述
33.125 和 100.667 代表了GC发生的时间。
日志开头的GC和Full GC说明了这次垃圾收集的停顿类型,而不是用来新生代GC还是老年代GC的。如果有Full,说明这次GC是发生了Stop The World的(如果是新生代收集器可能是因为分配担保失败而引起的)。
DefNew,Tenured,Perm表示GC发生的区域。Serial收集器新生代名为DefNew,如果在ParNew中这位ParNew,如果是PS收集器则为PSYoungGen。

内存分配与回收策略(规则)
1.对象优先在Eden中分配
大多数情况下对象在Eden中分配,如果Eden区没有足够的空间进行分配时,虚拟机将发起一次Minor GC。
Minor GC和Full GC的区别:
Minor GC(新生代GC):指发生在新生代的垃圾回收动作,因为Java对象大多都具备朝生夕灭的特性,所以Minor GC非常频繁,回收速度也比较快。
Full GC(老年代GC):指的是发生在老年代的GC,这个GC速度一般会比Minor GC慢10倍以上。
2.大对象直接进入老年代
所谓的大对象,就是需要大量连续内存空间的Java对象,典型的就是那种很长的字符创以及数组。
3.长期存活的对象将进入老年代
虚拟机给每个对象定义了一个对象年龄(Age)计数器。如果对象在Eden出生并且经过一次Minor GC后仍然存活,且能被Survivor容纳的话,就会移动到Survivor中,且年龄设置为1。在Survivor中没熬过一次Minor GC年龄就增加1,年龄增加到一定程度就会晋升到老年代中。
4.动态年龄判断
虚拟机并不是永远地要求对象的年龄必须达到一个固定值才能晋升老年代,如果Survivor中相同年龄的所有对象大小综合大于Survivor空间的一半,年龄大于等于该年龄的对象就可以直接进入老年代。
5.空间分配担保
在发生Minor GC之前,虚拟机会先检查老年代最大可用的连续空间是否大于新生代所有对象总空间,如果成立,Minor GC是安全的。否则就要看是否允许担保失败:
如果允许,会继续检查老年代最大可用连续空间是否大于历次晋升到老年代的对象的平均大小,如果大于,将尝试进行Minor GC,尽管是有风险的。
如果小于或者不允许,则要改为进行一次Full GC。

猜你喜欢

转载自blog.csdn.net/bianhao92115/article/details/83899824