著作权归作者所有,任何形式的转载都请联系作者获得授权并注明出处。
JVM参数类型
标准参数
基本上不变,相对比较稳定
- -help
- -server 、-client
- -version 、-showversion
- -cp 、-classpath
非标准化参数
在部分JVM里面会有变化,但是变化小
- -Xint:解释执行
- -Xcomp:第一次使用就编译成本地代码
- -Xmixed:混合模式,JVM自己来决定是否编译成本地代码
[root@localhost tmp]# java -version java version "1.8.0_101" Java(TM) SE Runtime Environment(build 1.8.0_101-b13) Java HotSpot(TM)64-Bit Server vM (build 25.101-b13. nixed mode[root@localhost tmp]#Ljava -Xint -version java version "1.8.0_101" Sava(TM)SE Runtime Environment (build 1.8.0_101-b13 Java HotSpot(TM)64-Bit Server vM (build 25.101-b13, interpreted mode [root@localhost tmp]# java -Xcomp-version Ac[root@localhost tmp]# java -Xcomp -version java version "1.8.0_101 Java(TM) SE Runtime Environment(build 1.8.0_101-b13) Java HotSpot(TM)64-Bit Server VM(build 25.101-b13, compiled mode [root@localhost tmp]#
XX参数
XX参数是非标准化参数、相对不稳定、主要用于JVM调优和Debug,分为2大类:
- Boolean类型
格式:-XX:[+-] 表示(+)启用或者禁用(-)name属性
比如:-XX:+UseConMarkSweepGC
-XX:UseG1GC - 非Boolean类型
格式:-XX: = 表示name的属性值是value
比如:-XX:MaxGCPauseMillis = 200
-XX:GCTimeRatio = 19
-Xmx(最大JVM内存)-Xms(最小JVM内在)
它不是X参数,而是XX参数
-Xms等价于-XX:InitialHeapSize
-Xmx等价于-XX:MaxHeapSize
在linux中查看java进程内存大小 jinfo -flag MaxHeapSize [进程ID]
[ root @ localhost tmp ]# jinfo - flag MaxHeapSize 23789- XX : MaxHeapsize =268435456
如何查看JVM运行时参数
- -XX:+PrintFlagsInitial 查看初始时的一个值
- -XX:+PrintFlagsFinal 查看最终的一个值
- -XX:+UnlockExperimentalVMOptions 解锁实验参数
- -XX:+UnlockDiagnosticVMOptions 解锁诊断参数
- -XX:+PrintCommandLineFlags 打印命令行参数
实例:java -XX:+PrintFlagsFinal -version
bool useGlGc = false [ product } bool UseGcLogFileRotation = false { product } bool useGcoverheadLimit =true
uintx InitialHeapsize :=130023424 [ product } uintx MaxHeapSize :=2053111808 { product } uintx MaxNewSize :@68419540
=表示默认值
:=被用户或者JVM修改后的值
jps
jps 命令类似与 linux 的 ps 命令,但是它只列出系统中所有的 Java 应用程序。 通过 jps 命令可以方便地查看 Java 进程的启动类、传入参数和 Java 虚拟机参数等信息。 具体参考jvm 性能调优工具之jps
[ weihu @iZ94r2ljas4Z order - biz - servicesl $ jps 6304 LoggerTimer .] ar 27085 Jps Iweihu @iZ94r2ljas4Z order - biz - servicesl $ jps - l 6304 libs / LoggerTimer . jar 27098 sun .to0 ls . JpS . Jps Iweihu @izo4r21jas4Z order - biz - services ]$
jinfo
查看一个JVM正在运行的参数值
[root@localhost tmp]# jps -1 31772 sun.tools.ips.Jps [root@loca7host tmp]#23789 org.apache.catalina.startup.Bootstrap jinfo -flag MaxHeapSize 23789查看tomcat最大内存 -XX:MaxHeapsize=268435456 [root@localhost tmp]# iinfo -flags 23789 查看当前进程的JVM运行时信息 Attaching to process ID 23789, please wait... Debugger attached successfully. JVM version is 25.101-b1 Server compiler detected不是默认JVM参数值,有被修改过,比如tomcat启动时的默认参数会修改JVM Non-default vm flags: ECICompilerCount=3 -XX:ConcGCThreads=1 -XX:+DisableExplicitGc -XX:G1HeapReaionsize=1048576 -XX:+ eapoumponoutotMemorverror -XX:HeapDumpPath=nu11 AX:InitialHeapSize=268435456 -XX:Markstacksize=4194304 -XX:MaxGCPauseMi1 is=200 -xx:MaxHeapsize=268435456 -xx:MaxMetaspaceSize=67108864’-xx:MaxNewsize=160432128 -xx:MetaspaceSize=67108864 -xx:Min ionAgeThreshold=3 HeapDe1taBvtes=1048576-XX:+Printgc -XX:+PrintGCDateStamps -XX:+PrintGCDetails -XX:+PrintGCTimeStamps -xX:strinaDed -XX:+UseCompressedc1assPointers -XX:+UseCompressedoops -XX:+UseFastUnorderedTimeStamps -XX:+UseG简 +UseStringDeduplication 20 apachejuli classLoadercogiagcerfigx:ilseGucc -Djava.uti1.1ogging.config.fi1e=/usr/1oca1/tomcat8_demo/conf/logging.properties -Djava.util.logging -XX:+UseStringDeduplication -xX:StringDeduplicationAgeThreshoa 4UseCompressedc1assPointers-xx:MaxGCPauseMi11is=200-Xms256M-Xmx256M-xx:MetaspaceSize=64M -XX:MaxMetaspaceSize=64M -XX+Disab1eExp1icitGc -XX:+HeapDumpOnoutofMemoryError -XX:HeapDumpPath=/usr/1oca1/tomcat8_demo/1ogs/-XX:+PrintGCDetails -xX+PrintGCTimeStamps -XX:+PrintGCDateStamps -x1oggc:/usr/1oca1/tomcat8_demo/1ogs/gc.1og -Djdk.t1s.ephemera1DHKeySize=2048 -D java.protoco1.handler.pkgs=org.apache.catalina.webresources -Dcatalina.base=/usr/local/tomcat8_demo -Dcatalina.home=/usr/ ocal/tomcat8_demo -Djava.io.tmpdir=/usr/local/tomcat8_demo/temp [root@localhost tmp]#
jinfo举例
- 查看最大内存
jinfo -flag MaxHeapSize [进程ID]
[ root @ localhost ~]# jinfo - flag MaxHeapsize 3176 KX : MaxHeapSize =2147483648
- 查看垃圾回收器
jinfo -flag UseConcMarkSweepGC/UseG1GC/UseParallelGC [进程ID]
[ root @ localhost ,~]# jinfo - flag useconcMarkSweepGc 3176 - XX :- UseConcMarkSweepGc [ root @ localhost ~]# jinfo - flag UseG1Gc3176 - XX :+ UseGlGC [ root @ localhost _~]# jinfo - flag useParal1elGc3176- XX :-UseParalle1Gc
使用jstat查看jvm统计信息
类加载信息
部分options: -class, -compiler,-gc, -printcompilation更多可点此处查看
垃圾收集信息
部分options: -gc, -gcutil,-gccause, -gcnew, -gcold更多可点此处查看
-gc输出结果参数说明:
- S0C、S1C、S0U:S0和S1的总量与使用量
- EC、EU:Eden区总量和使用量
- OC、OU:Old区总量和使用量
- MC、MU:Metaspace区总量和使用量
- CCSC、CCSU:压缩类空间总量和使用量
- YGC、YGCT:YoungGC的次数与时间
- FGC、FGCT:FullGC的次数与时间
- GCT:总的GC时间
JIT编译信息
部分options: -compiler, -printcompilation更多可点此处查看
- ag ttag > aTTeCLTy [ root @ localhost ~]# jstat - compiler 3176 compiled Failed Invalid / AbstractArchiveResourceSet getResource [ root @ localhost ~]# jstat - printcompilation 3176 compiled Size _ Type Method FailedType FailedMethod 8103 46.21 1 org / apache / catalina / webresources OLU J .1 com / fasterxml / jackson / core / io / Numberoutput outputInt
jmap+MAT分析内存溢出
实例测试项目基于spring boot快速搭建
User.java
public class User{ private int id; private String name; # 构造方法 # get() and set() } 复制代码
MemoryController.java
@RestController public class MemoryController{ private List<User> userList = new ArrayList<User>(); /** * 设置堆最大最小内存,方便快速调试(-Xmx32M -Xms32M) **/ @GetMapping("/heap") ##基于堆的内存溢出 public String heap(){ int i = 0; while(true){ userList.add(new User(i++, UUID.randomUUID().toString())); } } /** * 设置非堆最大最小内存(-XX:MetaspaceSize=32M -XX:MaxMetaspaceSize=32M) **/ @GetMapping("/noheap") ## 非堆的内存溢出 public String noheap(){ while(true){ ##基于动态生成class测试 classList.addAll(Metaspace.createClasses()); } } }
Metaspace.java
import java.util.ArrayList; import java.util.List; import org.objectweb.asm.ClassWriter; import org.objectweb.asm.MethodVisitor; import org.objectweb.asm.Opcodes; /* * 继承ClassLoader是为了方便调用defineClass方法,因为该方法的定义为protected * */ public class Metaspace extends ClassLoader { ## 类持有 List<Class<?>> classes = new ArrayList<Class<?>>(); ## 循环1000w次生成1000w个不同的类。 for (int i = 0; i < 10000000; ++i) { ClassWriter cw = new ClassWriter(0); ## 定义一个类名称为Class{i},它的访问域为public,父类为java.lang.Object,不实现任何接口 cw.visit(Opcodes.V1_1, Opcodes.ACC_PUBLIC, "Class" + i, null, "java/lang/Object", null); ## 定义构造函数<init>方法 MethodVisitor mw = cw.visitMethod(Opcodes.ACC_PUBLIC, "<init>","()V", null, null); ## 第一个指令为加载this mw.visitVarInsn(Opcodes.ALOAD, 0); ## 第二个指令为调用父类Object的构造函数 mw.visitMethodInsn(Opcodes.INVOKESPECIAL, "java/lang/Object", "<init>", "()V", false); ## 第三条指令为return mw.visitInsn(Opcodes.RETURN); mw.visitMaxs(1, 1); mw.visitEnd(); Metaspace test = new Metaspace(); byte[] code = cw.toByteArray(); ## 定义类 Class<?> exampleClass = test.defineClass("Class" + i, code, 0, code.length); classes.add(exampleClass); } }
访问路径localhost:8080/heap 堆内存溢出图示
main ] c . i . m . MonitorTuningApplication 180- exec -3] o . a . c . c . C .( Tomcat ]. llocalhost ]. Un 180- exec -3] o . s . web . servlet . DispatcherServlet 180- exec -3] o . s . web . servlet . DispatcherServlet Poller -1" Exception in thread " http - nio -8080- ClientPoller - O " java . lang . OutOfMemoryError : GC overh : Started MonitorTuningApplication in 5.606 seconds ( JVM running for 6.212: Initializing Spring FrameworkServlet ' dispatcherServlet ' : FrameworkServlet ' dispatcherServlet ': initialization started : FrameworkServlet ' dispatcherServlet ': initialization completed in 37 me
访问路径localhost:8080/noheap 非堆内存溢出图示
2018-05-23 22:40:43.077 INFO 18080---[ ost - startStop -1] o . s . b . w . servlet . FilterRegistratior 2018-05-23 22:40:43.078 INFO 18080---[ ost - startStop -1] o . s . b . w . servlet . FilterRegistratior 2018-05-23 22:40:43.248 INFO 18080---[ main ] o . s . w . s . handler . SimpleUrlHandlerV Exception in thread " main " java . lang . OutOfMemoryError : Metaspace Exception in thread " ContainerBackgroundProcessor [ StandardEngine [ Tomcatll " java . lang
导出应用程序内存映像文件
有2中方式可以导出,分别是:内存溢出自动导出、使用jmap命令手动导出
- 内存溢出自动导出——使用如下jvm参数选项
-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=./ ##要导出的文件路径
2018-05-23 22:49:43.131 INFO 20284---[ io -8080- exec -10] o . s . web . servlet . DispatcherServlet java . lang . OutOfMemoryError : GC overhead limit exceeded Dumping heap to .Ajavapid20284.hprof... Heap dump file created [45445309 bytes in 0.241 secs ] Exception in thread " http - nio -8080- ClientPoller ~1" java . lang . OutOfMemoryError : GC overhead limit exceeded Exception in thread " http - nio -8080- exec -10" java . lang . OutOfMemoryError . GC overhead limit gxceeded
- 使用jmap命令手动导出 部分options: -heap, -clstats, -dump:, -F更多可点此处查看
数据过大可能无法导出。
下图示例:
C :\ Usersxujs > jps -1 20184 8280 sun . tools . jps . Jps 16940 com imooc . monitor _ tuning . Moni torTuningApplication C : Users \ xujs > cd Desktop C :\ Users \ xujs \ Desktop > jmap - dump : format = b ,fi1e= heap . hprof 16940 Dumping heap to C : Users ( xujs Desktop Vheap . hprof ... Heap dump file created
使用MAT分析定位错误
jstack实战线程异常
Java的堆栈跟踪 - 为给定的进程或核心文件或远程调试服务器打印线程的堆栈跟踪。
选项 | 说明 |
-F | 当jstack[ -l] pid没有响应时强制执行堆栈转储。 |
-l | 打印有关锁的其他信息,例如拥有的可拥有java.util.concurrent同步器列表 |
-m | 打印具有Java和本机C / C ++帧的混合模式堆栈跟踪。 |
-H | 打印帮助信息。 |
-help | 打印帮助信息。 |
java线程的状态
下表列出了使用Control + Break Handler进行线程转储的可能线程状态。
线程状态 | 描述 |
NEW | 该主题尚未开始。 |
RUNNABLE | 线程正在JVM中执行。 |
BLOCKED | 线程被阻塞等待监视器锁定。 |
WAITING | 线程无限期地等待另一个线程执行特定操作。 |
TIMED_WAITING | 线程正在等待另一个线程执行最多指定等待时间的操作。 |
TERMINATED | 线程已经退出。 |
线程状态流转图
实例-CPU飙高
CpuController.java
import java.util.ArrayList; import java.util.List; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; @RestController public class CpuController { /** * 死循环 * */ @RequestMapping("/loop") public List<Long> loop(){ String data = "{\"data\":[{\"partnerid\":]"; return getPartneridsFromJson(data); } private Object lock1 = new Object(); private Object lock2 = new Object(); /** * 死锁 * */ @RequestMapping("/deadlock") public String deadlock(){ new Thread(()->{ synchronized(lock1) { try {Thread.sleep(1000);}catch(Exception e) {} synchronized(lock2) { System.out.println("Thread1 over"); } } }) .start(); new Thread(()->{ synchronized(lock2) { try {Thread.sleep(1000);}catch(Exception e) {} synchronized(lock1) { System.out.println("Thread2 over"); } } }) .start(); return "deadlock"; } public static List<Long> getPartneridsFromJson(String data){ ##{\"data\":[{\"partnerid\":982,\"count\":\"10000\",\"cityid\":\"11\"},{\"partnerid\":983,\"count\":\"10000\",\"cityid\":\"11\"},{\"partnerid\":984,\"count\":\"10000\",\"cityid\":\"11\"}]} ##上面是正常的数据 List<Long> list = new ArrayList<Long>(2); if(data == null || data.length() <= 0){ return list; } int datapos = data.indexOf("data"); if(datapos < 0){ return list; } int leftBracket = data.indexOf("[",datapos); int rightBracket= data.indexOf("]",datapos); if(leftBracket < 0 || rightBracket < 0){ return list; } String partners = data.substring(leftBracket+1,rightBracket); if(partners == null || partners.length() <= 0){ return list; } while(partners!=null && partners.length() > 0){ int idpos = partners.indexOf("partnerid"); if(idpos < 0){ break; } int colonpos = partners.indexOf(":",idpos); int commapos = partners.indexOf(",",idpos); if(colonpos < 0 || commapos < 0){ //partners = partners.substring(idpos+"partnerid".length()); #注释该部分代码抛出问题 continue; } String pid = partners.substring(colonpos+1,commapos); if(pid == null || pid.length() <= 0){ //partners = partners.substring(idpos+"partnerid".length()); #注释该部分代码抛出问题 continue; } try{ list.add(Long.parseLong(pid)); }catch(Exception e){ //do nothing } partners = partners.substring(commapos); } return list; } }
top命令查询Linux cpu
导出文件 jstack [进程ID] > [fileName]
对导出后的文件内容进行分析定位,可以参考
输出所有线程top -p [进程ID] -H
基于JVisualVM的可视化监控
监控本地tomcat
查看死锁,循环
查看热点方法执行时间
实时内存
修改插件中心地址
要选择jdk版本对应插件中心的地址
C :\ Users \ xujs > java - version java version 1.8.0_144 Java ( TM ) SE Runtime Environment ( build 1.8.0_144-b01) Java HotSpot ( TM )64- Bit Server VM ( build 25.144-b01, mixed mode )