本文主要内容: 算法
零、堆的回顾: 服务器
新生代中的98%对象都是“朝生夕死”的,因此并不须要按照1:1的比例来划份内存空间,而是将内存分为一块比较大的Eden空间和两块较小的Survivor空间,每次使用Eden和其中一块Survivor。当回收时,将Eden和Survivor中还存活着的对象一次性地复制到另一块Survivor空间上,最后清理掉Eden和刚才用过的Survivor空间。HotSpot虚拟机默认Eden和Survivor的大小比例是8:1,也就是说,每次新生代中可用内存空间为整个新生代容量的90%(80%+10%),只有10%的空间会被浪费。 多线程
固然,98%的对象可回收只是通常场景下的数据,咱们没有办法保证每次回收都只有很少于10%的对象存活,当Survivor空间不够用时,须要依赖于老年代进行分配担保,因此大对象直接进入老年代。 架构
堆的结构以下图所示: 并发
垃圾收集器: 性能
若是说收集算法时内存回收的方法论,那么垃圾收集器就是内存回收的具体实现。 网站
虽然咱们在对各类收集器进行比较,但并不是为了挑出一个最好的收集器。由于直到如今位置尚未最好的收集器出现,更加没有万能的收集器,因此咱们选择的只是对具体应用最合适的收集器。 spa
1、串行收集器:Serial收集器 线程
新生代、老年代都会使用串行回收 设计
新生代复制算法
老年代标记-整理
总结:Serial收集器对于运行在Client模式下的虚拟机来讲是一个很好的选择。
这个收集器是一个单线程的收集器,但它的单线程的意义并不只仅说明它只会使用一个CPU或一条收集线程去完成垃圾收集工做,更重要的是在它进行垃圾收集时,必须暂停其余全部的工做线程,直到它收集结束。收集器的运行过程以下图所示:
2、并行收集器:
一、ParNew收集器:
新生代并行
老年代串行
二、Parallel Scanvenge收集器:
三、Parallel Old收集器:
以下图所示:
各类参数设置:
最大停顿时间,单位毫秒
GC尽力保证回收时间不超过设定值
0-100的取值范围
垃圾收集时间占总时间的比
默认99,即最大容许1%时间作GC
注:这两个参数是矛盾的。由于停顿时间和吞吐量不可能同时调优。咱们一方买但愿停顿时间少,另一方面但愿吞吐量高,其实这是矛盾的。由于:在GC的时候,垃圾回收的工做总量是不变的,若是将停顿时间减小,那频率就会提升;既然频率提升了,说明就会频繁的进行GC,那吞吐量就会减小,性能就会下降。
吞吐量:CPU用于用户代码的时间/CPU总消耗时间的比值,即=运行用户代码的时间/(运行用户代码时间+垃圾收集时间)。好比,虚拟机总共运行了100分钟,其中垃圾收集花掉1分钟,那吞吐量就是99%。
注2:以上全部的收集器当中,当执行GC时,都会stop the world,可是下面的CMS收集器却不会这样。
3、CMS收集器:
CMS收集器(Concurrent Mark Sweep:并发标记清除)是一种以获取最短回收停顿时间为目标的收集器。适合应用在互联网站或者B/S系统的服务器上,这类应用尤为重视服务器的响应速度,但愿系统停顿时间最短。
注:这里的并发指的是与用户线程一块儿执行。
二、CMS收集器运行过程:(着重实现了标记的过程)
(1)初始标记
根能够直接关联到的对象
速度快
(2)并发标记(和用户线程一块儿)
主要标记过程,标记所有对象
(3)从新标记
因为并发标记时,用户线程依然运行,所以在正式清理前,再作修正
(4)并发清除(和用户线程一块儿)
基于标记结果,直接清理对象
整个过程以下图所示:
其中,初始标记和从新标记时,须要stop the world。
整个过程当中耗时最长的是并发标记和并发清除,这两个过程均可以和用户线程一块儿工做。
打印GC日志举例以下:
三、CMS收集器特色:
(1)尽量下降停顿
(2)会影响系统总体吞吐量和性能
好比,在用户线程运行过程当中,分一半CPU去作GC,系统性能在GC阶段,反应速度就降低一半
(3)清理不完全
由于在清理阶段,用户线程还在运行,会产生新的垃圾,没法清理
(4)由于和用户线程一块儿运行,不能在空间快满时再清理
-XX:CMSInitiatingOccupancyFraction设置触发GC的阈值
若是不幸内存预留空间不够,就会引发concurrent mode failure
咱们来看一下concurrent mode failure的日志:
碰到上图中的状况,咱们须要使用串行收集器做为后备。
四、既然标记清除算法会形成内存空间的碎片化,CMS收集器为何使用标记清除算法而不是使用标记整理算法:
答案:
CMS收集器更加关注停顿,它在作GC的时候是和用户线程一块儿工做的(并发执行),若是使用标记整理算法的话,那么在清理的时候就会去移动可用对象的内存空间,那么应用程序的线程就颇有可能找不到应用对象在哪里。
为了解决碎片的问题,CMS收集器会有一些整理上的参数,接下来就来说这个。
五、整理时的各类参数:
Full GC后,进行一次整理。整理过程是独占的,会引发停顿时间变长
设置进行几回Full GC后,进行一次碎片整理
设定CMS的线程数量
4、GC参数的整理:
-XX:+UseSerialGC:在新生代和老年代使用串行收集器
-XX:SurvivorRatio:设置eden区大小和survivior区大小的比例
-XX:NewRatio:新生代和老年代的比
-XX:+UseParNewGC:在新生代使用并行收集器
-XX:+UseParallelGC :新生代使用并行回收收集器
-XX:+UseParallelOldGC:老年代使用并行回收收集器
-XX:ParallelGCThreads:设置用于垃圾回收的线程数
-XX:+UseConcMarkSweepGC:新生代使用并行收集器,老年代使用CMS+串行收集器
-XX:ParallelCMSThreads:设定CMS的线程数量
-XX:CMSInitiatingOccupancyFraction:设置CMS收集器在老年代空间被使用多少后触发
-XX:+UseCMSCompactAtFullCollection:设置CMS收集器在完成垃圾收集后是否要进行一次内存碎片的整理
-XX:CMSFullGCsBeforeCompaction:设定进行多少次CMS垃圾回收后,进行一次内存压缩
-XX:+CMSClassUnloadingEnabled:容许对类元数据进行回收
-XX:CMSInitiatingPermOccupancyFraction:当永久区占用率达到这一百分比时,启动CMS回收
-XX:UseCMSInitiatingOccupancyOnly:表示只在到达阀值的时候,才进行CMS回收
最后的总结:
为了减轻GC压力,咱们须要注意些什么?