博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Java线上程序频繁JVM FGC问题排障与启示
阅读量:1982 次
发布时间:2019-04-27

本文共 2838 字,大约阅读时间需要 9 分钟。

线上Java程序的JVM频繁FGC,现象如图所示:

一直持续FGC 5次左右,每次耗时1秒多不等。

FGC的原因实际上是内存不够用,但是运维反映堆内存是2G,从运维提供的参数看也是。

内存实际上一直只用到1G以内。

 

这时候可以自己写一段代码输出堆内存数据,这是最准的:

public class JVMTest {    public static void main(String[] args) throws Exception {    MemoryMXBean mxb = ManagementFactory.getMemoryMXBean();        //Heap        System.out.println("Max:" + mxb.getHeapMemoryUsage().getMax() / 1024 / 1024 + "MB");    //Max:1776MB        System.out.println("Init:" + mxb.getHeapMemoryUsage().getInit() / 1024 / 1024 + "MB");  //Init:126MB        System.out.println("Committed:" + mxb.getHeapMemoryUsage().getCommitted() / 1024 / 1024 + "MB");   //Committed:121MB        System.out.println("Used:" + mxb.getHeapMemoryUsage().getUsed() / 1024 / 1024 + "MB");  //Used:7MB        System.out.println(mxb.getHeapMemoryUsage().toString());    //init = 132120576(129024K) used = 8076528(7887K) committed = 126877696(123904K) max = 1862270976(1818624K)        //Non heap        System.out.println("Max:" + mxb.getNonHeapMemoryUsage().getMax() / 1024 / 1024 + "MB");    //Max:0MB        System.out.println("Init:" + mxb.getNonHeapMemoryUsage().getInit() / 1024 / 1024 + "MB");  //Init:2MB        System.out.println("Committed:" + mxb.getNonHeapMemoryUsage().getCommitted() / 1024 / 1024 + "MB");   //Committed:8MB        System.out.println("Used:" + mxb.getNonHeapMemoryUsage().getUsed() / 1024 / 1024 + "MB");  //Used:7MB        System.out.println(mxb.getNonHeapMemoryUsage().toString());    //init = 2555904(2496K) used = 7802056(7619K) committed = 9109504(8896K) max = -1(-1K)    }}

参考: 

 

这是本地的测试数据,很明显自己设定的内存都生效了,然后拿到线上一跑果然实际堆最大内存是900多M,所以内存触发了阈值就FGC。所以FGC的根源还是内存不够,运维设置不对,运维设置了2G,但是实际上由于使用上的问题不生效

所以要用数据说话,不要去猜测,也不要过度相信配置,因为已经FGC了,而且内存上不了1G。

java    -Xms64m #JVM启动时的初始堆大小    -Xmx128m #最大堆大小    -Xmn64m #年轻代的大小,其余的空间是老年代    -XX:MaxMetaspaceSize=128m #    -XX:CompressedClassSpaceSize=64m #使用 -XX:CompressedClassSpaceSize 设置为压缩类空间保留的最大内存。    -Xss256k #线程    -XX:InitialCodeCacheSize=4m #    -XX:ReservedCodeCacheSize=8m # 这是由 JIT(即时)编译器编译为本地代码的本机代码(如JNI)或 Java 方法的空间    -XX:MaxDirectMemorySize=16m    -XX:NativeMemoryTracking=summary #开启内存追踪    -jar app.jar

#java -Xms2048m -Xmx2048m  -Xmn64m   -cp Test-1.0.0.jar com.test.JVMTest  start

这个只是本地模拟,线上参数需要比这个复杂。

 

再回到前面的问题为什么回运维设置不生效呢?

因为这个原因:

Java 8u131及以上版本开始支持了Docker的cpu和memory限制。

cpu limit

即如果没有显式指定-XX:ParalllelGCThreads 或者 -XX:CICompilerCount, 那么JVM使用docker的cpu限制。如果docker有指定cpu limit,jvm参数也有指定-XX:ParalllelGCThreads 或者 -XX:CICompilerCount,那么以指定的参数为准。

memory limit

在java8u131+及java9,需要加上-XX:+UnlockExperimentalVMOptions -XX:+UseCGroupMemoryLimitForHeap才能使得Xmx感知docker的memory limit。

-XX:+UnlockExperimentalVMOptions -XX:+UseCGroupMemoryLimitForHeap (正确的识别容器限制,910.50M)安全

关于这个解释可以参考此文即可:

具体使用不使用这个参数需要结合实际情况。

 

后来据运维说是参数配置问题:

java -server -jar XXX.jar -Xms2048m -Xmx2048m 这是错的

java -server -jar -Xms2048m -Xmx2048m XXX.jar 要这样

延申阅读:

转载地址:http://ilrpf.baihongyu.com/

你可能感兴趣的文章
【NLP学习笔记】知识图谱阅读笔记及其心得
查看>>
【工具使用】新版CSDN-markdown编辑器使用指南
查看>>
《知识图谱》阅读笔记(六)
查看>>
【NLP学习笔记】中文分词(Word Segmentation,WS)
查看>>
【NLP学习笔记】词性标注(Part-of-speech Tagging, POS)
查看>>
【NLP学习笔记】语义角色标注 (Semantic Role Labeling, SRL)
查看>>
《知识图谱》阅读笔记(七)
查看>>
《知识图谱》阅读笔记(九)
查看>>
【超越白皮书7】你需要知道关于ETH2.0的几个事实
查看>>
超越白皮书8:穿云而过的闪电网络
查看>>
AMM做市无常损失对冲分析系列(一)—— 损益及期权对冲模型构建
查看>>
JS中document对象和window对象有什么区别
查看>>
【python练习题】遍历1
查看>>
【matlab】显示图片且下方显示文字
查看>>
关于greater<int>以及类模板的一些理解
查看>>
对于时间复杂度的通俗理解
查看>>
如何输入多组数据并输出每组数据的和?
查看>>
基于CentOS 7的Linux常用命令行命令
查看>>
行阶梯型矩阵
查看>>
信号量机制
查看>>