一、JVM概述

1、为什么要调优

1、防止出现OOM
2、解决OOM问题
3、减少Full GC频率
4、提高系统稳定性

2、性能优化的步骤

1)性能监控

主要监控GC频率、CPU、OOM问题、内存泄露、死锁、程序响应时间等问题;

2)性能分析

1、使用http://gceasy.io来分析GC日志
2、灵活使用命令行工具:jps、jstack、jstat、jmap、jinfo等
3、导出dump文件,使用内存分析工具分析
4、使用Arthas、jconsole、JVisualVM等工具实事查看JVM状态

3)性能调优

1、增加内存
2、优化代码
3、增加机器,分散服务器压力
4、合理分配线程数量
5、使用中间件进行缓存

4、性能指标

1、响应时间
2、吞吐量
3、并发数
4、内存占用

二、JVM监控及诊断之命令

1、jps(Java Process Status)

1)用途:

1、查看正在运行的Java进程

2)基本语法

jps [options]  [hostid]
options参数:
-q:仅仅显示本地虚拟机id
-l:输出应用程序全类名
-m:列出虚拟机进程启动时传递主类的main()的参数
-v:列出虚拟机进程启动时的JVM参数

2、jstat(JVM Statistics Monitoring Tool)

1)用途:

1、用于监视虚拟机各种运行状态信息的命令行工具,可以显示本地或者远程中的类装载、内存、垃圾收集、JIT等状态;

2)基本语法

jstat -<option> [-t] [-h<lines>] <vmid> [<interval> [<count>]]
option参数:

> 类装载相关的:
	-class:显示ClassLoader的相关信息: 类的装载、卸载数量、总空间、类装载所消耗的时间等;

> 垃圾回收相关的:
	-gc:显示与GC相关的堆信息,包括Eden区、两个Survivor区、老年代、永久代等的容量、已用空间、GC时间合计等信息
	-gccapacity:显示内容与-gc基本相同,但输出主要关注Java堆各个区域使用到的最大、最小空间
	-gcutil:显示内容与-gc基本相同,但输出主要关注已使用空间占总空间的百分比。
	-gccause:与-gcutil功能一-样,但是会额外输出导致最后一次或当前正在发生的GC产生的原因
	-gcnew:显示新生代GC状况
	-gcnewcapacity:显示内容与-gcnew基本相同,输出主要关注使用到的最大、最小空间
	-geold:显示老年代GC状况
	-gcoldcapacity:显示内容与-gcold基本相同,输出主要关注使用到的最大、最小空间
	-gcpermcapacity:显示永久代使用到的最大、最小空间
	
> JIT相关的:
	-compiler:显示JIT编译器编译过的方法、耗时等信息
	-printcompilation:输出已经被JIT编译的方法
interval参数:用于指定输出统计数据的周期,单位为毫秒。即:查询间隔
count参数:用于查询的总次数
-t:可以在输出信息前加上一个Timestamp列,显示程序的运行时间。单位:秒
-h:可以在周期性数据输出时,输出多少行数据后输出一个表头信息

3、jinfo(Configration Info for Java)

1)用途:

1、查看虚拟机配置参数信息,也可用于调整虛拟机的配置参数。

2)基本语法

jinfo [options] pid
查看配置信息:
jinfo sysprops <进程ID>  # 可以查看由System.getProperties()取得的参数
jinfo flags <进程ID> # 查看曾经赋过值的一些参数
jinfo flag <进程ID> # 查看某个Java进程的具体参数

修改配置信息:
jinfo -flag [+|-]参数名称 <进程ID>
jinfo -flag 参数名称=参数值 <进程ID>

拓展:
java -XX:+PrintFlagsInitial # 查看所有JVM参数启动的初始值
java -XX:+PrintFlagsFinal # 查看所有JVM参数的最终值
java -参数名称 +PrintCommandLineFlags # 查看哪些已经被用户或者JVM设置过的参数的名称和值

4、jmap(Java Memory map)

1)用途:

1、导出dump文件,获取java进程的内存相关信息;

2)基本语法

jmap [option] <pid>
option参数:
-dump:生成Java堆快照文件
-heap:输出整个堆空间的详细信息,包括GC的使用.堆配置信息,以及内存的使用信息等
-histo:输出堆中对象的同级信息,包括类、实例数量和合计容量
-permstat:以ClassLoader为统计口径输出永久代的内存状态信息(仅linux/solaris平台有效)
-finalizerinfo:显示在F-Queue中等待Finalizer线程执行finalize方法的对象(仅linux/solaris平台有效)
-F:强制生成dump文件
> 导数内存映射文件:
	手动方式:
	jmap dump:format=b,file=<filename.hprof> <pid>
	jmap dump:live,format=b,file=<filename.hprof> <pid>
	自动方式:
	-XX:HeapDumpOnOutOfMemoryError
	-XX:HeapDumpPath=<filename.hprof>

5、jhat(JVM Heap Analysis Tool)

1)用途:

1、JDK自带堆分析工具

2)基本语法

jhat [option] [dumpfile]
option参数:
-stack false|true # 关闭|打开对象分配调用栈跟踪
-refs false|true # 关闭|打开对象引用跟踪
-port port-number # 设置 jhat HTTP Server 端口号,默认7000
-exclude exclude-file # 执行对象查询时需要排除的数据成员
-baseline exclude-file # 指定一个基准堆转储
-debug int # 设置debug级别

6、jstack(Java Stack Trace)

1)用途:

1、打印jvm中线程快照

2)基本语法

jstack [option] <pid>
-F:当正常输出的请求不被响应时,强制输出线程堆栈
-l:除堆栈外,显示关于锁的信息
-m:如果调用本地方法的话,可以显示C/C++的堆栈

7、jcmd(Java Command)

1)用途:

1、多功能命令行,可以实现除了jstat之外的所有命令的功能

2)基本语法

jcmd -l # 列出所有JVM进程
jcmd 进程号 help # 针对指定的进程,列出支持的所有具体命令
jcmd 进程号 具体命令 # 显示指定进程的指定命令的数据

8、jstatd(Java Statistics Monitoring Daemon)

1)用途:

1、远程主机信息收集,此命令是一个RMI Server应用程序,提供了对JVM的创建和结束监视,也为远程监视工具提供了一个可以attach的接口

2)基本语法

jstatd [options]
options参数:
-nr # 当一个存在的RMI Registry没有找到时,不尝试创建一个内部的RMI Registry
-p port # 端口号,默认为1099
-n rminame # 默认为JStatRemoteHost;如果多个jstatd服务开始在同一台主机上,rminame唯一确定一个jstatd服务
-J # jvm选项

三、JVM常用GUI工具

1、JDK自带工具

1、jconsole:JDK自带的可视化监控工具,查看Java应用程序的运行概况、监控堆信息、永久区(或元空间)使用情况、类加载情况等;
2、Visual VM:Visual VM是一个工具,它提供了一个可视界面,用于查看Java虚拟机上运行的基于Java技术的应用程序的详细信息;
3、JMC:Java Mission Control,内置Java Flight Recorder,能够以极低的性能开销收集Java虚拟机的性能数据。

2、第三方工具

1、MAT
2、JProfiler

四、JVM常用参数

1、JVM参数类型

类型一:标准参数选项
1、以 - 开头
2、Hotspot VM有两种模式,分别是server和client
类型二:-X参数选项
1、以-X开头
2、JVM的JIT编译模式相关的选项:-Xint解释模式、-Xcomp编译模式、-Xmixed混合模式
3、-Xms -Xmx -Xss参数分别是-XX:InitialHeapSize、-XX:MaxHeapSize、-XX:ThreadStackSize的缩写
类型三:-XX参数选项
1、以-XX开头
2、Boolean类型:
-XX:+<option> # 表示启用option属性
-XX:-<option> # 表示禁用option属性
3、非Boolean类型:
-XX:<option>=<number>
-XX:<option>=<string>
4、-XX:+PrintFlagsFinal
	输出所有参数的名称和默认值
	默认不包括Diagnostic和Experimental的参数
	可以配合-XX:+UnlockDiagnosticVMOptions和-XX:UnlockExperimentalVMOptions使用

2、常用JVM参数选项

1、打印设置的-XX选项及值

-XX:+PrintCommandLineFlags
-XX:+PrintFlagsInitial
-XX:+PrintFlagsFinal
-XX:+PrintVMOptions

2、堆、栈、方法区等内存大小的设置

> 栈:
-Xss1024k # 设置每个线程的栈大小

> 堆:
-Xms1024k # 初始堆大小
-Xmx1024k # 最大堆大小
-Xmn1024k # 设置年轻代初始值和最大值都是1024k
-XX:NewSize=1024m # 新生代初始值大小
-XX:MaxNewSize=1024m # 新生代最大值大小
-XX:SurvivorRatio=8 # 新生代中Eden区和Survivor区的比值,默认为8
-XX:+UserAdaptiveSizePolicy # 自动选择区大小比例,默认开启
-XX:NewRatio=2 # 设置新生代与老年代的比值,默认为2
-XX:PretenureSizeThreadshold=1024 # 设置大于此阈值对象直接分配到老年代,单位字节(只对Serial、ParNew收集器有效)
-XX:MaxTenuringThreshold=15 # 新生代每次MinorGC后,存活对象age+1,当对象年龄大于设置的这个值时就进入老年代 ,默认15
-XX:+PrintTenuringDistribution # 让JVM在每次MinorGC后打印出当前使用的Survivor对象的年龄分布
-XX:TargetSurvivorRatio # 表示MinorGC结束后Survivor区域中占用空间的期望比例

> 方法区:
	永久代:
	-XX:PermSize=256m # 设置初始值大小
	-XX:MaxPermSize=256m # 设置最大值大小
	元空间:
	-XX:MetaspaceSize # 初始值大小
	-XX:MaxMetaspaceSize # 最大值大小
	-XX:+UseCompressedOops # 使用压缩对象指针
	-XX:+UserCompressedClassPointers # 使用压缩类指针
	-XX:CompressedClassSpaceSize # 设置Class Metaspace的大小,默认1G
> 直接内存
	-XX:MaxDirectMemorySize # 指定内存容量,默认和堆最大值一样

3、OOM相关选项

-XX:+HeapDumpOnOutMemoryError # 内存出现OOM时,生成Dump文件
-XX:+HeapDumpBeforeFullGC # 出现FullGC之前,生成Heap转储文件
# -XX:+HeapDumpOnOutMemoryError与-XX:+HeapDumpBeforeFullGC两者只能设置一个
-XX:HeapDumpPath=<path> # 指定Heap转储文件路径
-XX:OnOutOfMemoryError # 当发生OOM时,指定一个脚本路劲,并执行这个脚本

4、垃圾收集器相关选项

5、GC日志相关选项

常用参数:
-verbose:gc # 输出日志信息,默认标准输出
-XX:+PrintGC # 打印简化版GC日志
-XX:+PrintGCDetails # 打印GC详细日志
-XX:+PrintGCTimeStamps # 程序启动到发生GC的时间秒数
-XX:+PrintGCDateStamps # 输出GC发生的时间戳,必须配合-XX:PrintGCDeails使用
-XX:+PrintHeapAtGC # 每次GC前和GC后,都打印堆信息
-Xloggc<file>  # 把GC日志写入一个文件中
其他参数:
-XX:TraceClassLoading # 监控类的加载
-XX:PrintGCApplicationStoppedTime # 打印GC时线程的停顿时间
-XX:+PrintGCApplicationConcurrentTime # 垃圾收集之前打印出应用未中断的执行时间
-XX:+PrintReferenceGC # 记录回收了多少种不同引用类型的引用
-XX:PrintTenuringDistribution # 让JVM在每次MinorGC后打印出当前使用的Survivor中对象的年龄分布
-XX:+UseGCLogFileRotation # 启用GC日志文件的自动转储
-XX:NumberOfGCLogFiles=1 # GC日志文件的循环数目
-XX:GCLogFileSize=1M # 控制GC日志文件的大小

6、其他参数

-XX:+DisableExplicitGC # 禁用hotshot执行System.gc,默认禁用
-XX:ReservedCodeCacheSize=<size>[G|M|K] # 指定代码缓存大小
-XX:+UseCodeCacheFlushing # 使用该参数让JVM放弃一些被编译的代码,避免代码缓存被占满时JVM切换到interpreted-only的情况
-XX:+DoEscapeAnalysis # 开启逃逸分析
-XX:+UseBiasedLocking # 开启偏向锁
-XX:+UseLargePages # 开启使用大页面
-XX:+PrintTLAB # 打印TLAB的使用情况
-XX:TLABSize # 设置TLAB的大小