ZGC实践
0、JDK 17配置VM_PARAM-server -Xmx22g -Xms22g -Xss512k -XX:MaxDirectMemorySize1024m -XX:HeapDumpOnOutOfMemoryError -XX:InitialCodeCacheSize512m -XX:ReservedCodeCacheSize512m -XX:UnlockExperimentalVMOptions -XX:UseZGC -XX:UnlockDiagnosticVMOptions -XX:ZAllocationSpikeTolerance3 -XX:ConcGCThreads12 -XX:ZStatisticsInterval30 -Xlog:safepoint,classhisto*trace,age*,gc*info:file/opt/logs/logs/gc-%t.log:time,tid,tags:filecount5,filesize50m -Dio.netty.tryReflectionSetAccessibletrue --add-opens java.base/java.langALL-UNNAMED --add-opens java.base/java.ioALL-UNNAMED --add-opens java.base/java.mathALL-UNNAMED --add-opens java.base/java.netALL-UNNAMED --add-opens java.base/java.nioALL-UNNAMED --add-opens java.base/java.securityALL-UNNAMED --add-opens java.base/java.textALL-UNNAMED --add-opens java.base/java.timeALL-UNNAMED --add-opens java.base/java.utilALL-UNNAMED --add-opens java.base/java.util.concurrentALL-UNNAMED --add-opens java.base/java.util.concurrent.locksALL-UNNAMED --add-opens java.base/java.util.concurrent.atomicALL-UNNAMED --add-opens java.base/jdk.internal.accessALL-UNNAMED --add-opens java.base/jdk.internal.miscALL-UNNAMED --add-opens java.base/sun.reflect.generics.reflectiveObjectsALL-UNNAMED --add-opens java.base/jdk.internal.perfALL-UNNAMED --add-opens java.base/java.instrumentALL-UNNAMED --add-opens jdk.attach/sun.tools.attachALL-UNNAMED --add-opensjava.base/java.lang.reflectALL-UNNAMED -Djava.security.egdfile:/dev/./urandom1、秒杀期间性能出现毛刺原因自适应算法长时间没GC流量突增新对象创建过快GC不及时对象将堆占满引起内存分配阻塞导致停顿GC日志且停顿时GC日志中有大量的“Allocation Stall”日志解决方案增大修正系数-XX:ZAllocationSpikeTolerance更早出发GC开启“基于固定时间间隔”的GC触发机制-XX:ZCollectionIntervalJDK 11JDK 17用ZProactive参数启用主动 GC空闲时预防性回收默认开启2、压测时cpu出现抖动原因开启“固定时间间隔”的GC触发机制ZCollectionInterval设置过小导致GC比较频繁GC日志日志中关键字是“Timer”解决方案调大“固定时间间隔”使“固定时间间隔”的GC触发机制作为兜底策略调小并发线程数ConcGCThreads3、压测时性能尖刺性能尖刺一般两个原因CPU负载过高不能及时处理请求任务GC导致STW原因内存和回收速率过慢引起内存分配阻塞导致停顿频繁GCGC日志日志中关键字是“Allocation Rate”解决方案增大并发标记和并行回收速率速度调整ConcGCThreads和ParallelGCThreads参数反复调整压测4、单次GC时间20ms与预期的10ms差距较大原因dump内存文件发现系统中ClassLoader实例比较多ClassLoader属于GC Roots一部分切ZGC停顿时间与GC Roots的数量成正比GC日志:观察ZGC日志统计group:name发现“Pause Roots ClassLoaderDataGraph”一项耗时较长。解决方案服务是之前两个项目合并的很多重复无用代码优化无用代码删除业务中不使用的类5、长时间不重启接口性能变差分析通过arthas分析dump内存分析发现耗时的原因主要是因为日志打印最终定位org.apache.logging.log4j.util.StackLocator:calcLocation()的耗时stackLocatorcalcLacation解决方案要改bugjkd维度团队段时间无法支持最终通过升级jdk 17解决log4j打印日志时避免打印日志类和行会导致定位问题困难StackLocator:calcLocation()耗时原因Log4j2 打异步日志的时候如果需要保留日志产生的类还有行号需要缓存堆栈通过StackWalker来获取线程的调用堆栈JVM查找方法时会调用ResolvedMethodTable::lookup而ResolvedMethodTable是一个只有1007个bucket的hash表因为bucket较小产生冲突的可能性较大处理冲突的办法是开链法。当链表越来越长时查找的性能将急剧下降。每次调用StackWalker遍历栈帧的时候每个栈帧都会生成一个ResolvedMethodName对象放到jvm中的ResolvedMethodTable中但jdk11的zgc不能有效清理其中不用的对象。因为ResolvedMethodTable是个定容的hashtable随着其中的数据越来越多每个bucket的单链表越来越长查询效率会越来越慢触发条件jdk11zgclog4j参考文档https://cloud.tencent.com/developer/article/1778169https://blog.csdn.net/My_Way666/article/details/110857839