1. 垃圾收集算法
标记清除算法 标记整理算法 复制算法 分代算法
2. 垃圾收集器
serial parallel CMS(Concurrent Mark Sweep) g1
3. 垃圾收集器干的活儿
找到不再使用的对象,回收它们占用的内存, 对堆的内存布局进行压缩整理
4. 应用程序的特性
1. 对最大响应时间敏感
2. 对吞吐量敏感
应用程序的性能目标:最大响应时间, 平均响应时间......
5. GC调优基础
5.1 调整堆的大小
如果堆过小,则可能频繁GC,影响运行应用程序的逻辑;
如果堆过大,虽然GC频率降低,但一次GC的持续时间会变长(总的停顿时间=GC频率 * 一次GC耗时);
如果堆过大, 可能还会使用操作系统的虚拟内存(这个涉及换页,访问硬盘,极其昂贵的操作),那会更慢(这个要杜绝);
因此,调整堆大小时首要的原则就是永远不要讲堆的容量设置的比机器的物理内存还大。若有多个JVM实例,则所有JVM实例的堆的总和要小于机器物理内存,当然还应该考虑给操作系统,其他应用程序预留一些内存。通常情况,对于普通的操作系统,应该预留至少1G的内存空间。
另外,一个经验法则是完成Full GC后,应该释放出70%的空间。
5.2 代空间的调整
指定新生代大小,那剩下的就是老年代。
代的划分对性能的影响:如果新生代分配的比较大,新生代垃圾收集发生的频率就比较低,从新生代晋升到老年代的对象也会比较少。但新生代分配的比较大的话,老年代就会比较小,比较容易被填满,那就会比较频繁的发生full gc。这个找到一个恰当的平衡点是问题的关键。
试图通过指定新生代的最大及最小值区间的方式调优新生代的结果是十分困难的。
-XX:+PrintTenuringDistribution:打印Survivor区的年龄分布情况,如果年龄都很小,Survivor区的使用率经常达到阈值,说明Survivor区有点小了。
5.3 永久代和元空间的调整
5.4 控制并发
并行或者并发垃圾收集器的线程数由参数-XX:ParallelGCThread=N控制。对下面这些操作,这个参数值会影响线程的数目:
1)使用-XX:+UseParallelGC收集新生代空间
2)使用-XX:+UseParallelOldGC收集老年代空间
3)使用-XX:+UseParNewGC收集新生代空间
4)使用-XX:+UseG1GC收集新生代空间
5)CMS收集器的“时空停顿”阶段(但并非full gc)
6) G1收集器的“时空停顿”阶段(但并非full gc)
并行或者并发GC时,为了尽可能缩短“时空停顿”的时间,JVM要启动合适数量的线程来充分利用CPU。
默认情况,JVM会在机器的每一个CPU上运行一个线程,最多同时运行8个。一旦达到这个上限,JVM会调整算法,每超出5/8个CPU启动一个新线程。所以总线程数:ParallelGCThreads=8+((N-8)*5/8) N是CPU个数。
当这个计算方式不合适时,就需要用户手动指定并发线程数了。
5.5 自适应调整
根据调优的策略,JVM会不断地尝试,寻找优化性能的机会,所以在JVM的运行过程中,堆、代以及survivor空间的大小都可能发生变化。6. 垃圾收集器
7. 垃圾收集算法:CMS
7.1 CMS Minor GC
以上是CMS Young GC的GC日志。
新生代总大小629M;GC前,新生代被占用629M;GC后,新生代被占用69M(都在survivor区)。
堆总大小2027M;GC前,堆被占用1303M;GC后,堆被占用772M。
并行的垃圾收集线程消耗了0.42秒的cpu时间,但整个过程实际耗时0.12秒。
7.2 CMS Concurrent Cycle (CMS并发周期)
7.3 CMS Concurrent mode failure (CMS并发模式失效)
7.4 CMS promotion failed (CMS晋升失败)
7.5 调优
7.5.1 针对并发模式失效的调优
以更高的频率运行后台回收线程
使用更多的后台回收线程
增大老年代空间