先给各位看一个最终的调优参数
{
"XX:+UseG1GC": "-XX:+UseG1GC",
"XX:MaxGCPauseMillis": "-XX:MaxGCPauseMillis=200",
"Xms": "-Xms24000m",
"Xmx": "-Xmx24000m",
"Xss": "-Xss256k",
"XX:MetaspaceSize": "-XX:MetaspaceSize=256m",
"XX:MaxMetaspaceSize": "-XX:MaxMetaspaceSize=256m",
"-XX:+UnlockExperimentalVMOptions": "-XX:+UnlockExperimentalVMOptions",
"-XX:-ResizePLAB": "-XX:-ResizePLAB",
"-XX:G1NewSizePercent": "-XX:G1NewSizePercent=3",
"-XX:G1ReservePercent": "-XX:G1ReservePercent=15",
"-XX:MaxTenuringThreshold": "-XX:MaxTenuringThreshold=8",
"-XX:G1HeapRegionSize": "-XX:G1HeapRegionSize=16m",
"-XX:ConcGCThreads": "-XX:ConcGCThreads=4",
"-XX:ParallelGCThreads": "-XX:ParallelGCThreads=8",
"-XX:InitiatingHeapOccupancyPercent": "-XX:InitiatingHeapOccupancyPercent=60",
"-XX:G1HeapWastePercent": "-XX:G1HeapWastePercent=20",
"-XX:+PrintHeapAtGC": "-XX:+PrintHeapAtGC",
"-XX:+PrintTenuringDistribution": "-XX:+PrintTenuringDistribution",
"XX:-OmitStackTraceInFastThrow": "-XX:-OmitStackTraceInFastThrow",
"XX:SoftRefLRUPolicyMSPerMB": "-XX:SoftRefLRUPolicyMSPerMB=0",
"Xloggc": "-Xloggc:${SERVER_LOG}/gc-${TIMESTAMP}.log",
"XX:+PrintGC": "-XX:+PrintGC",
"XX:+PrintGCDetails": "-XX:+PrintGCDetails",
"XX:+PrintGCDateStamps": "-XX:+PrintGCDateStamps",
"XX:+HeapDumpOnOutOfMemoryError": "-XX:+HeapDumpOnOutOfMemoryError",
"XX:HeapDumpPath": "-XX:HeapDumpPath=${SERVER_LOG}"
}
在8C32G的机器上 应用的主要目的是处理流试数据,属于消息驱动型应用
- -XX:+UseG1GC
开启G1垃圾回收
- -XX:MaxGCPauseMillis=200
垃圾回收最大停顿时间单位ms,G1垃圾回收正常情况下都是young GC和mix GC,如果出现了full GC就需要调整了。一般的Full GC会STW超过10s
- -Xms24000m -Xmx24000m
设置jvm的堆内存,当前机器是32G,很多公司的默认设置是机器内存的一半,剩下的需要预留给系统其它配置, 比如filebeat,zabbix等。这个需要具体自己估计了。
- -Xss256k
设置单个线程的栈的大小,在非常线程多的情况下可以适当调整这个值,但是操作系统对一个进程内的线程数还是有限制的,不能无限生成,经验值在3000~5000左右。 如果频繁创建销毁,可以不用那么大,256K足够。默认是1m
- -XX:MetaspaceSize=256m -XX:MaxMetaspaceSize=256m
元空间的大小,一般256M就足够了,这个无脑配置即可
- -XX:+UnlockExperimentalVMOptions
一些jvm的特殊参数,默认是没有打开的,需要使用这个开关开启之后才能使用, 比如在java8u131+及java9,需要加上-XX:+UnlockExperimentalVMOptions -XX:+UseCGroupMemoryLimitForHeap才能使得Xmx感知docker的memory limit。
- -XX:-ResizePLAB
当应用开启的线程较多时,最好使用-XX:-ResizePLAB来关闭PLAB()的大小调整,以避免大量的线程通信所导致的性能下降。
- -XX:G1ReservePercent=15
G1会预留一部分内存,制造一个假天花板,防止to-space的方式。模式是10,为了避免释放空间是吧,特意增加了这个天花板的厚度。
- -XX:G1NewSizePercent=3
G1年轻代的大小,按照经验一般保证在800M~1G,太大容易导致单词young GC的时间太长,太短又增加频率。1g差不多能保证每次GC在100ms的时间。
- -XX:MaxTenuringThreshold=8
进入年老代的年龄,默认是15,每个对象的对象头中有一个4个bit位的数字来表示年龄,4个bit最大为15, 这个字段需要经验和调优了,在这个系统中,一般认为经理过8次yang GC的还没有释放的对象,可以粗略的认为老年人了。
- -XX:G1HeapRegionSize=16m
G1是将内存划分为区域进行处理的,这个参数表明,每个区域的大小,保证1k~2k之间的区域数量。
- -XX:ConcGCThreads=4
GC阶段需要做并发标记,这个就是并发标记的线程数量,不要配置满了,因为标记的同时,应用还需要跑。 当前机器是8C,所以我的并发标记设置成4。能加快标记速度。
- -XX:ParallelGCThreads=8
ParallelGCThreads值的具体算法,具体如下:
- 如果用户显示指定了ParallelGCThreads,则使用用户指定的值。
- 否则,需要根据实际的CPU所能够支持的线程数来计算ParallelGCThreads的值,计算方法见步骤③和步骤④。
- 如果物理CPU所能够支持线程数小于8,则ParallelGCThreads的值为CPU所支持的线程数。这里的阀值为8,是因为JVM中调用nof_parallel_worker_threads接口所传入的switch_pt的值均为8。
- 如果物理CPU所能够支持线程数大于8,则ParallelGCThreads的值为8加上一个调整值,调整值的计算方式为:物理CPU所支持的线程数减去8所得值的5/8或者5/16,JVM会根据实际的情况来选择具体是乘以5/8还是5/16。 比如,在64线程的x86 CPU上,如果用户未指定ParallelGCThreads的值,则默认的计算方式为:ParallelGCThreads = 8 + (64 - 8) * (5/8) = 8 + 35 = 43。
- -XX:InitiatingHeapOccupancyPercent=60
当整个堆的内存使用量占用到了多少开始进行GC,默认是45
- -XX:G1HeapWastePercent=20
G1主要的GC方式是young GC+ mixed GC,这个参数的意思是当可回收的内存超过这个比例时,G1才开始mixed gc。 没有垃圾就不做mixed GC了。
- -XX:SoftRefLRUPolicyMSPerMB=0
这个参数我认为可能有点用, 官方解释是softly reachable objects will remain alive for some amount of time after the last time they were referenced. The default value is one second of lifetime per free megabyte in the heap。 很多系统见到现在都是设置为0,没必要等1秒;
- 其他
其他的都是一些出问题的时候一些日志是否打印。
如何分析GC日志
懂的都懂。。。https://gceasy.io/
我就不分析下去了。