(未完结)JAVA7 JVM调优 测试环境

先说明下这里是测试环境实验,并且JVM调优要根据项目和运行实际情况来进行调整,极端情况不可按部就班
测试环境如下:1个1核2线程的CPU(2个逻辑CPU),8G内存,JDK:1.7,tomcat:8.5.70,JVM参数为默认
先在 catalina.sh 中添加参数打印GC信息到日志文件
JAVA_OPTS="-XX:+PrintGCDetails -Xloggc:/opt/logs/gc.log"
优化项1
(未完结)JAVA7 JVM调优 测试环境
文章图片

默认情况堆最小空间和最大空间不一致,为了避免每次垃圾回收完成后JVM重新分配内存,调整为一致,默认最小为总内存1/64,最大为1/4 通过计算有一定偏差,手动设置为最小和最大都为2G
JAVA_OPTS="-Xms2G -Xmx2G -XX:+PrintGCDetails -Xloggc:/opt/logs/gc.log"
启动后通过jstat -gc -h 10 pid 1s 查看pid jvm中各空间使用情况 1秒刷新一次 保留10行
(未完结)JAVA7 JVM调优 测试环境
文章图片

发现S1 大小在YOUNG GC后会发生变化,通过资料查询发现可能是自动调整功能(猜测)
(未完结)JAVA7 JVM调优 测试环境
文章图片

(猜测) S1使用过程中, 将上一次复制过来的数据清理后存活的大小按一定比例存放, 即:不占据过多空间。S0使用过程中, 将S1扩容至S0大小,防止S0和Eden数据复制过来再大幅度扩容
【(未完结)JAVA7 JVM调优 测试环境】我添加了-XX:SurvivorRatio=8 让S0 和 S1 同样大小 占年轻代1/10, 这样young GC 后 S0 S1容量不再发生变化,便于调试变化的值
(未完结)JAVA7 JVM调优 测试环境
文章图片

内存分配到这里结束了,下面就是垃圾回收器的选择,官方JDK7这方面描述的比较少,这里参考8的官方文档探索一下
垃圾回收器主要考虑在老年代的回收,因为青年代大部分不到15岁就被清除了(一次young gc 算一岁,默认15次)
CMS(Concurrent Mark Sweep) 主要用于老年代的垃圾回收, 年轻代仍适用串行或并行的方式进行垃圾回收, 相比于并行收集器,采用并发标记来减少STW时间。但同样有一定的缺点,比如老年代清除后有空间碎片,如果有一个大对象进入老年代,没有连续的空间进行过存储,将进行一次不必要的Full GC,而且在并行标记时也会占用更多的CPU。
清除步骤如下:

  1. 初始标记(CMS initial mark):独占CPU,stop-the-world, 仅标记GCroots能直接关联的对象,速度比较快;
  2. 并发标记(CMS concurrent mark):可以和用户线程并发执行,通过GCRoots Tracing 标记所有可达对象;
  3. 重新标记(CMS remark):独占CPU,stop-the-world, 对并发标记阶段用户线程运行产生的垃圾对象进行标记修正,以及更新逃逸对象;
  4. 并发清理(CMS concurrent sweep):可以和用户线程并发执行,清理在重复标记中被标记为可回收的对象。
CMS 收集器在并发收集周期中两次暂停应用程序。第一个暂停是将可从根直接访问的对象(例如,来自应用程序线程堆栈和寄存器的对象引用、静态对象等)和堆中的其他地方(例如,年轻代)标记为活动对象。第一次暂停称为初始标记。第二次暂停出现在并发标记结束时,它会在 CMS 收集器完成并发标记后查找由于应用程序线程更新对象中的引用而被并发跟踪遗漏的对象叫做重新标记。
G1(Garbage-First) 垃圾收集器是一种服务器式垃圾收集器,针对具有大内存的多处理器机器。它试图以高概率满足垃圾收集 (GC) 暂停时间目标,同时实现高吞吐量。全堆操作(例如全局标记)与应用程序线程同时执行。这可以防止与堆或实时数据大小成正比的中断。其他的垃圾回收相比, G1弱化了分代的情况, 用了Region的结构来替代新生代年老代。
资料:
JAVA7官方JVM调优白皮书
JAVA7官方JVM参数
JAVA各版本官网文档
CMS垃圾回收器
G1垃圾回收期
借鉴了大神的CMS与G1区别

    推荐阅读