怀抱观古今,寝食展戏谑。这篇文章主要讲述JVM核心参数配置常用调试命令工具与调优思路相关的知识,希望能为你提供帮助。
JVM核心参数配置、常用调试命令工具与调优思路
- 所有JVM相关参数,比较好看的表格分类,参考:
虽然是JDK 7的,但是也有较大的参考价值。
- JDK官方技术手册 ,参考:
这个就相当好了,第5章的
java
小节就有所有jvm相关参数。1 JVM参数 1.1 日志参数
日志参数 | 作用 |
---|---|
-XX:+PrintGC | 查看GC基本信息 |
-XX:+PrintGCDetails | 查看GC详细信息 |
-XX:+PrintGCDateStamps< br> -XX:+PrintGCTimeStamps | 查看GC时间,单独使用时没有效果,可以与查看GC信息的参数结合使用 |
-XX:+PrintHeapAtGC | 查看GC前后堆、方法区可用容量变化 |
-XX:+PrintGCApplicationConcurrentTime< br> -XX:+PrintGCApplicationStoppedTime | 查看GC过程中用户线程并发时间以及停顿的时间 |
-XX:+PrintTenuringDistribution | 查看熬过收集后剩余对象的年龄分布信息 |
-XX:+UseGCLogFileRotation | 打开或关闭GC日志滚动记录功能,要求必须设置 -Xloggc参数 |
-XX:NumberOfGCLogFiles=5 | 设置滚动日志文件的个数,必须大于1,日志文件命名策略是,< filename> .0, < filename> .1, ..., < filename> .n-1,其中n是该参数的值 |
-XX:GCLogFileSize=20M | 设置滚动日志文件的大小,必须大于8k,当前写日志文件大小超过该参数值时,日志将写入下一个文件 |
-Xloggc:/home/GCEASY/gc.log | gc日志路径 |
public class TmpTest public static void main(String[] args)
byte[] obj = new byte[1024 * 1024];
obj = null;
System.gc();
1.1.1 -XX:+PrintGC
[GC (System.gc())4352K->
536K(125952K), 0.0007552 secs]
[Full GC (System.gc())536K->
395K(125952K), 0.0036377 secs]
1.1.2 -XX:+PrintGCDetails包含的信息有:发生了GC的区域、该区域GC前后内存变化(清除了多少空间、增加了多少空间、该区域当前内存容量)、总的堆内存变化、Metaspace内存变化以及最后面的各区域内存情况。
[GC (System.gc()) [PSYoungGen: 4352K->
528K(38400K)] 4352K->
536K(125952K), 0.0016053 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
[Full GC (System.gc()) [PSYoungGen: 528K->
0K(38400K)] [ParOldGen: 8K->
392K(87552K)] 536K->
392K(125952K), [Metaspace: 3237K->
3237K(1056768K)], 0.0045798 secs] [Times: user=0.01 sys=0.00, real=0.01 secs]
Heap
PSYoungGentotal 38400K, used 998K [0x0000000795580000, 0x0000000798000000, 0x00000007c0000000)
eden space 33280K, 3% used [0x0000000795580000,0x0000000795679b20,0x0000000797600000)
from space 5120K, 0% used [0x0000000797600000,0x0000000797600000,0x0000000797b00000)
tospace 5120K, 0% used [0x0000000797b00000,0x0000000797b00000,0x0000000798000000)
ParOldGentotal 87552K, used 392K [0x0000000740000000, 0x0000000745580000, 0x0000000795580000)
object space 87552K, 0% used [0x0000000740000000,0x0000000740062248,0x0000000745580000)
Metaspaceused 3256K, capacity 4496K, committed 4864K, reserved 1056768K
class spaceused 357K, capacity 388K, committed 512K, reserved 1048576K
1.1.3 -XX:+PrintGCDateStamps与-XX:+PrintGCDetails结合使用的效果:
2020-01-13T01:10:45.422-0800: [GC (System.gc()) [PSYoungGen: 4352K->
480K(38400K)] 4352K->
488K(125952K), 0.0018664 secs] [Times: user=0.01 sys=0.00, real=0.00 secs]
2020-01-13T01:10:45.424-0800: [Full GC (System.gc()) [PSYoungGen: 480K->
0K(38400K)] [ParOldGen: 8K->
392K(87552K)] 488K->
392K(125952K), [Metaspace: 3224K->
3224K(1056768K)], 0.0071912 secs] [Times: user=0.00 sys=0.00, real=0.01 secs]
Heap
PSYoungGentotal 38400K, used 998K [0x0000000795580000, 0x0000000798000000, 0x00000007c0000000)
eden space 33280K, 3% used [0x0000000795580000,0x0000000795679b20,0x0000000797600000)
from space 5120K, 0% used [0x0000000797600000,0x0000000797600000,0x0000000797b00000)
tospace 5120K, 0% used [0x0000000797b00000,0x0000000797b00000,0x0000000798000000)
ParOldGentotal 87552K, used 392K [0x0000000740000000, 0x0000000745580000, 0x0000000795580000)
object space 87552K, 0% used [0x0000000740000000,0x0000000740062110,0x0000000745580000)
Metaspaceused 3256K, capacity 4496K, committed 4864K, reserved 1056768K
class spaceused 357K, capacity 388K, committed 512K, reserved 1048576K
1.1.4 -XX:+PrintHeapAtGC
Heap before GC invocations=1 (full 0):
PSYoungGentotal 38400K, used 3686K [0x0000000795580000, 0x0000000798000000, 0x00000007c0000000)
eden space 33280K, 11% used [0x0000000795580000,0x0000000795919a38,0x0000000797600000)
from space 5120K, 0% used [0x0000000797b00000,0x0000000797b00000,0x0000000798000000)
tospace 5120K, 0% used [0x0000000797600000,0x0000000797600000,0x0000000797b00000)
ParOldGentotal 87552K, used 0K [0x0000000740000000, 0x0000000745580000, 0x0000000795580000)
object space 87552K, 0% used [0x0000000740000000,0x0000000740000000,0x0000000745580000)
Metaspaceused 3284K, capacity 4496K, committed 4864K, reserved 1056768K
class spaceused 361K, capacity 388K, committed 512K, reserved 1048576K
Heap after GC invocations=1 (full 0):
PSYoungGentotal 38400K, used 448K [0x0000000795580000, 0x0000000798000000, 0x00000007c0000000)
eden space 33280K, 0% used [0x0000000795580000,0x0000000795580000,0x0000000797600000)
from space 5120K, 8% used [0x0000000797600000,0x0000000797670020,0x0000000797b00000)
tospace 5120K, 0% used [0x0000000797b00000,0x0000000797b00000,0x0000000798000000)
ParOldGentotal 87552K, used 8K [0x0000000740000000, 0x0000000745580000, 0x0000000795580000)
object space 87552K, 0% used [0x0000000740000000,0x0000000740002000,0x0000000745580000)
Metaspaceused 3284K, capacity 4496K, committed 4864K, reserved 1056768K
class spaceused 361K, capacity 388K, committed 512K, reserved 1048576KHeap before GC invocations=2 (full 1):
PSYoungGentotal 38400K, used 448K [0x0000000795580000, 0x0000000798000000, 0x00000007c0000000)
eden space 33280K, 0% used [0x0000000795580000,0x0000000795580000,0x0000000797600000)
from space 5120K, 8% used [0x0000000797600000,0x0000000797670020,0x0000000797b00000)
tospace 5120K, 0% used [0x0000000797b00000,0x0000000797b00000,0x0000000798000000)
ParOldGentotal 87552K, used 8K [0x0000000740000000, 0x0000000745580000, 0x0000000795580000)
object space 87552K, 0% used [0x0000000740000000,0x0000000740002000,0x0000000745580000)
Metaspaceused 3284K, capacity 4496K, committed 4864K, reserved 1056768K
class spaceused 361K, capacity 388K, committed 512K, reserved 1048576K
Heap after GC invocations=2 (full 1):
PSYoungGentotal 38400K, used 0K [0x0000000795580000, 0x0000000798000000, 0x00000007c0000000)
eden space 33280K, 0% used [0x0000000795580000,0x0000000795580000,0x0000000797600000)
from space 5120K, 0% used [0x0000000797600000,0x0000000797600000,0x0000000797b00000)
tospace 5120K, 0% used [0x0000000797b00000,0x0000000797b00000,0x0000000798000000)
ParOldGentotal 87552K, used 395K [0x0000000740000000, 0x0000000745580000, 0x0000000795580000)
object space 87552K, 0% used [0x0000000740000000,0x0000000740062f80,0x0000000745580000)
Metaspaceused 3284K, capacity 4496K, committed 4864K, reserved 1056768K
class spaceused 361K, capacity 388K, committed 512K, reserved 1048576K
1.1.5 -XX:+PrintGCApplicationConcurrentTime
Application time: 0.0031662 seconds
Total time for which application threads were stopped: 0.0043566 seconds, Stopping threads took: 0.0000299 seconds
Application time: 0.0016923 seconds
1.1.6 -XX:+PrintTenuringDistribution
Desired survivor size 5242880 bytes, new threshold 7 (max 15)
1.1.7 -Xloggc:filename比如使用下面的gc参数:
-XX:+PrintGCDetails -XX:+PrintGCDateStamps -Xloggc:/Users/yeyonghao/gc.log
那么在我的系统上会有下面的日志:
$ cat gc.log
Java HotSpot(TM) 64-Bit Server VM (25.181-b13) for bsd-amd64 JRE (1.8.0_181-b13), built on Jul7 2018 01:02:31 by "java_re" with gcc 4.2.1 (Based on Apple Inc. build 5658) (LLVM build 2336.11.00)
Memory: 4k page, physical 8388608k(141640k free)/proc/meminfo:CommandLine flags: -XX:InitialHeapSize=134217728 -XX:MaxHeapSize=2147483648 -XX:+PrintGC -XX:+PrintGCDateStamps -XX:+PrintGCDetails -XX:+PrintGCTimeStamps -XX:+UseCompressedClassPointers -XX:+UseCompressedOops -XX:+UseParallelGC
2020-01-13T01:18:33.490-0800: 0.163: [GC (System.gc()) [PSYoungGen: 4352K->
416K(38400K)] 4352K->
416K(125952K), 0.0028668 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
2020-01-13T01:18:33.493-0800: 0.166: [Full GC (System.gc()) [PSYoungGen: 416K->
0K(38400K)] [ParOldGen: 0K->
388K(87552K)] 416K->
388K(125952K), [Metaspace: 3178K->
3178K(1056768K)], 0.0043444 secs] [Times: user=0.01 sys=0.00, real=0.00 secs]
Heap
PSYoungGentotal 38400K, used 998K [0x0000000795580000, 0x0000000798000000, 0x00000007c0000000)
eden space 33280K, 3% used [0x0000000795580000,0x0000000795679b28,0x0000000797600000)
from space 5120K, 0% used [0x0000000797600000,0x0000000797600000,0x0000000797b00000)
tospace 5120K, 0% used [0x0000000797b00000,0x0000000797b00000,0x0000000798000000)
ParOldGentotal 87552K, used 388K [0x0000000740000000, 0x0000000745580000, 0x0000000795580000)
object space 87552K, 0% used [0x0000000740000000,0x0000000740061000,0x0000000745580000)
Metaspaceused 3192K, capacity 4496K, committed 4864K, reserved 1056768K
class spaceused 354K, capacity 388K, committed 512K, reserved 1048576K
1.1.8 生产环境推荐可以给GC日志的文件后缀加上时间戳,当JVM重启以后,会生成新的日志文件,新的日志也不会覆盖老的日志,只需要在日志文件名中添加%t的后缀即可:
-XX:+PrintGCDetails
-XX:+PrintGCDateStamps
-Xloggc:/home/GCEASY/gc-%t.log
%t会给文件名添加时间戳后缀,格式是YYYY-MM-DD_HH-MM-SS。这样就非常简单了克服了UseGCLogFileRotation存在的所有的问题!
在我的系统上尝试,会生成下面的gc文件:
gc-2020-01-13_01-23-23.log
注意它表示的是当前系统时区的本地时间,不是UTC时间。
1.2 HeapDump参数
参数 | 作用 |
---|---|
-XX:+HeapDumpOnOutOfMemoryError | 发生java.lang.OutOfMemoryError时,将堆转储到文件中。 |
-XX:HeapDumpPath=./java_pid <
pid>
.hprof| 保存堆转储文件的路径。默认会在当前程序运行路径下生成dump文件,如: java_pid27023.hprof` |
|
-XX:OnOutOfMemoryError="
&
lt;
cmd args&
gt;
;
&
lt;
br/&
gt;
&
lt;
cmd args&
gt;
"
|
抛出OutOfMemoryError时,运行用户定义的命令(比如可以删除之前的dump文件,避免占用较多磁盘空间,或者是其它策略) |
-XX:ErrorFile=./hs_err_pid&
lt;
pid&
gt;
.log |
如果发生错误,将错误数据保存到文件中。 |
-XX:OnError="
&
lt;
cmd args&
gt;
;
&
lt;
cmd args&
gt;
"
|
发生错误时,运行用户定义的命令。 |
-XX:+CrashOnOutOfMemoryError | 会在当前运行目录生成hs_err_pid&
lt;
pid&
gt;
.log 日志文件 |
public class HeapOOM static class OOMObject public static void main(String[] args)
ArrayList<
OOMObject>
list = new ArrayList<
>
();
while (true)
list.add(new OOMObject());
配置下面的jvm参数:
-Xms20m
-Xmx20m
-XX:+HeapDumpOnOutOfMemoryError
-XX:HeapDumpPath=/tmp/log/MyApp_dump.hprof
-XX:OnOutOfMemoryError="mv /tmp/log/MyApp_dump.hprof /tmp/log/MyApp_dump_%p.hprof"
执行程序后,会有下面的提示:
java.lang.OutOfMemoryError: Java heap space
Dumping heap to /tmp/log/MyApp_dump.hprof ...
Heap dump file created [27953782 bytes in 0.119 secs]
#
# java.lang.OutOfMemoryError: Java heap space
# -XX:OnOutOfMemoryError="mv /tmp/log/MyApp_dump.hprof /tmp/log/MyApp_dump_%p.hprof"
#Executing "mv /tmp/log/MyApp_dump.hprof /tmp/log/MyApp_dump_27587.hprof"...
这时可以看到在
/tmp/log
目录下有新生成的dump文件:$ ls
MyApp_dump_27587.hprof
如果再发生溢出时,还会生成新的dump文件:
$ ls
MyApp_dump_27587.hprof MyApp_dump_27611.hprof
1.3 内存与收集器参数
1.3.1 收集器总览【JVM核心参数配置常用调试命令工具与调优思路】其组合如下:
文章图片
1.3.2 内存参数关于Java虚拟机的内存分布情况,可以参考:
文章图片
参数 | 作用 |
---|---|
-Xms256m | 设置初始堆内存大小 |
-Xmx512m | 设置最大堆内存大小< br> 需要注意的是,即使当前堆内存大小还没有达到最大堆内存大小,这部分内存也会被JVM虚拟机锁定 |
-Xss512k | 设置java虚拟机栈大小 |
-XX:MaxMetaspaceSize=Nm | 设置元空间最大值,默认是一个很大的值,即表示不限制,或者说只受限于本地内存大小 |
-XX:MetaspaceSize=Nm | 指定元空间的初始大小,达到该值就会触发垃圾收集进行类型卸载,同时收集器会对该值进行调整:如果释放了大量的空间,就适当降低该值;如果释放了很少的空间,那么在不超过-XX:MaxMetaspaceSize(如果设置了的话)的情况下,适当提高该值 |
-XX:MinMetaspaceFreeRatio | 作用是在垃圾收集之后控制最小的元空间剩余容量的百分比,可减少因为元空间不足导致的垃圾收集的频率。当进行过Metaspace GC之后,会计算当前Metaspace的空闲空间比,如果空闲比小于这个参数,那么虚拟机将增长Metaspace的大小。在本机该参数的默认值为40,也就是40%(这个没验证过)。设置该参数可以控制Metaspace的增长的速度,太小的值会导致Metaspace增长的缓慢,Metaspace的使用逐渐趋于饱和,可能会影响之后类的加载。而太大的值会导致Metaspace增长的过快,浪费内存 |
-XX:MaxMetaspaceFreeRatio | 用于控制最大的元空间剩余容量的百分比。当进行过Metaspace GC之后, 会计算当前Metaspace的空闲空间比,如果空闲比大于这个参数,那么虚拟机会释放Metaspace的部分空间。在本机该参数的默认值为70,也就是70%(这个没验证过) |
-XX:ReservedCodeCacheSize=64m | Java代码在执行时一旦被编译器编译为机器码,下一次执行的时候就会直接执行编译后的代码,也就是说,编译后的代码被缓存了起来。缓存编译后的机器码的内存区域就是codeCache。这是一块独立于Java堆之外的内存区域。除了JIT编译的代码之外,Java所使用的本地方法代码(JNI)也会存在codeCache中< br/> 可参考:https://juejin.im/post/5aebf997f265da0ba76f99db |
参数 | 作用 | 特定收集器 |
---|---|---|
-XX:SurvivorRatio=n | 新生代中Eden区域与Survivor区域的容量比值,默认为8,代表Eden:Survivor=8:1 | / |
–XX:NewRatio=n | 老年代与新生代的容量比值,默认为2,代表Old:Young=2:1 | / |
-XX:PretenureSizeThreshold=n | 直接晋升到老年代的对象大小,设置这个参数后,大于这个参数的对象将直接在老年代分配。n为字节数,如3145728,即3MB | 只对Serial和ParNew两款新生代收集器有效 |
-XX:MaxTenuringThreshold=n | 晋升到老年代的对象年龄。每个对象在坚持过一次Minor GC之后,年龄就增加1,当超过这个参数值时就进入老年代 | / |
-XX:+HandlePromotionFailure | 是否允许分配担保失败,即老年代的剩余空间不足以应付新生代的整个Eden和Survivor区的所有对象都存活的极端情况。详细参考Note1的说明。 | / |
-XX:ParallelGCThreads=n | 设置并行GC时进行内存回收的线程数,不同的JVM平台其默认值不同 | / |
-XX:GCTimeRatio=n | GC时间占总时间的比率,默认值为99,即允许1%的GC时间。仅在使用Parallel Scavenge收集器时生效 | Parallel Scavenge |
-XX:+DisableExplicitGC | 不允许通过调用System.gc()来触发GC | / |
下面参数是特定收集器 | ||
-XX:UseSerialGC | 虚拟机运行在Client模式下的默认值,打开此开关后,使用Serial + Serial Old的收集器组合进行内存回收 | Serial< br> Serial Old |
-XX:UseParNewGC | 打开此开关后,使用ParNew + Serial Old的收集器组合进行内存回收,在JDK 9后不再支持 | ParNew< br> Serial Old |
-XX:UseConcMarkSweepGC | 打开此开关后,使用ParNew + CMS + Serial Old的收集器组合进行内存回收。Serial Old收集器将作为CMS收集器出现“Concurrent Mode Failure”失败后的后备收集器使用 | ParNew< br> CMS< br> Serial Old |
-XX:UseParallelGC | JDK9之前虚拟机运行在Server模式下的默认值,打开此开关后,使用Parallel Scavenge + Serial Old(PS MarkSweep)的收集器组合 | Parallel Scavenge< br> Serial Old |
-XX:UseParallelOldGC | 打开此开关后,使用Parallel Scavenge + Parallel Old的收集器 | Parallel Scavenge< br> Parallel Old |
-XX:MaxGCPauseMillis | 设置GC的最大停顿时间。仅在使用Parallel Scavenge收集器时生效 | Parallel Scavenge |
-XX:CMSInitiatingOccupancyFraction=70 | 设置CMS收集器在老年代空间被使用多少后触发垃圾收集。默认值为68%,仅在使用CMS收集器时生效 | CMS |
-XX:+UseCMSInitiatingOccupancyOnly | 只是用设定的回收阈值(上面指定的70%),如果不指定,JVM仅在第一次使用设定值,后续则自动调整 | CMS |
-XX:+UseCMSCompactAtFullCollection | 设置CMS收集器在完成垃圾收集后是否要进行一次内存碎片整理,从JDK9开始废除该参数 | CMS |
-XX:CMSFullGCsBeforeCompaction=n | 设置CMS收集器在进行若干次垃圾收集后再启动一次内存碎片整理,从JDK9开始废除该参数 | CMS |
1.4.1 默认参数查看可以通过下面命令来获取当前使用的jdk的所有默认参数:
yeyonghao@yeyonghaodeMacBook-Pro:/tmp/log$ java -XX:+PrintFlagsInitial >
defaultFlags.log
yeyonghao@yeyonghaodeMacBook-Pro:/tmp/log$ wc -l defaultFlags.log
726 defaultFlags.log
可以看到在我使用的jdk环境有700多个参数。
比如想查看
MetaspaceSize
的默认大小是多少:$ grep MetaspaceSize defaultFlags.log
uintx InitialBootClassLoaderMetaspaceSize= 4194304product
uintx MaxMetaspaceSize= 18446744073709551615product
uintx MetaspaceSize= 21810376pd product
可以看到MetaspaceSize的默认大小为20M:
>
>
>
21810376 / 1024 / 1024
20
比如再看一下
CompressedClassSpaceSize
:$ grep CompressedClassSpaceSize defaultFlags.log
uintx CompressedClassSpaceSize= 1073741824product
它的默认大小为1G:
>
>
>
1073741824 / 1024 / 1024
1024
1.4.2 运行参数查看使用
jps -v
可以查看虚拟机启动时显式指定的参数列表,但如果想知道未被显式指定参数的系统默认值,除了去找资料外,就只能使用jinfo的-flag选项进行查询了。比如查看
CompressedClassSpaceSize
:$ jinfo -flag CompressedClassSpaceSize 16900
-XX:CompressedClassSpaceSize=1073741824
它的大小为1G:
>
>
>
1073741824 / 1024 / 1024
1024
相当于是使用了默认值。
比如查看
MaxMetaspaceSize
:$ jinfo -flag MaxMetaspaceSize 16900
-XX:MaxMetaspaceSize=18446744073709547520
它的默认最大空间为不限制,即使用了默认值,能分配多少空间取决于操作系统内存大小。
2 监控与调试工具 2.1 jps
jps [ options ] [ hostid ]
各参数说明如下:
选项 | 作用 |
---|---|
-q | 只输出LVMID,省略主类的名称 |
-m | 输出虚拟机进程启动时传递给主类main()函数的参数 |
-l | 输出主类的全名,如果进程执行的是JAR包,则输出JAR路径 |
-v | 输出虚拟机进程启动时的JVM参数 |
jps -lvm
。2.2 jstat
jstat [ option vmid [interval[s|ms] [count]] ]
参数interval和count代表查询间隔和次数,如果省略这2个参数,说明只查询一次。假设需要每250毫秒查询一次进程2764垃圾收集状况,一共查询20次,那命令是:
jstat -gc 2764 250 20
选项option代表用户希望查询的虚拟机信息,主要分为三类:类加载、垃圾收集、运行期编译状况。各参数说明如下:
选项 | 作用 |
---|---|
-class | 监视类加载、卸载数量、总空间以及类装载所耗费的时间 |
-gc | 监视Java堆状况,包括Eden区、2个Survivor区、老年代、Metaspace等的容量,已用空间,垃圾收集时间合计等信息 |
-gccapacity | 监视内容与-gc基本相同,但输出主要关注Java堆各个区域用到的最大、最小空间 |
-gcutil | 监视内容与-gc基本相同,但输出主要关注已使用空间占总空间的百分比 |
-gccause | 与-gcutil功能一样,但是会额外输出导致上一次垃圾收集产生的原因 |
-gcnew | 监视新生代垃圾收集状况 |
-gcnewcapacity | 监视内容与-gcnew基本相同,输出主要关注使用到的最大、最小空间 |
-gcold | 监视老年代垃圾收集状况 |
-gcoldcapacity | 监视内容与-gcold基本相同,输出主要关注使用到的最大、最小空间 |
-gcmetacapacity | 输出方法区使用到的最大、最小空间 |
-compiler | 输出即时编译器编译过的方法、耗时等信息 |
-printcompilation | 输出已经被即时编译的方法 |
2.3.1 -class监视类加载、卸载数量、总空间以及类装载所耗费的时间。
$ jstat -class 550
LoadedBytesUnloadedBytesTime
47184 99829.01317.646.01
2.3.2 -gc监视Java堆状况,包括Eden区、2个Survivor区、老年代、Metaspace等的容量,已用空间,垃圾收集时间合计等信息。
$ jstat -gc 550
S0CS1CS0US1UECEUOCOUMCMUCCSCCCSUYGCYGCTFGCFGCTGCT
4352.0 4352.00.02853.3 34944.00.0235236.0205519.5289032.0 277047.8 41412.0 36925.1530.50100.0000.501
空间容量信息:
SOC
:Survivor0区域空间容量(kB);S1C
:Survivor1区域空间容量(kB);S0U
:Survivor0区域空间使用量(kB);S1U
:Survivor1区域空间使用量(kB);EC
:Eden区域空间容量(kB);EU
:Eden区域空间使用量(kB);OC
:Old区域空间容量(kB);OU
:Old区域空间使用量(kB);MC
:Metaspace区域空间容量(kB);MU
:Metaspace区域空间使用量(kB);CCSC
:CompressedClass区域空间使容量(kB);CCSU
:CompressedClass区域空间使用量(kB);
YGC
:Young GC事件次数;YGCT
:Young GC事件所用的总时间(s);FGC
:Full GC事件次数;FGCT
:Full GC事件所用的总时间(s);GCT
:GC事件所用的总时间(s),即YGCT + FGCT;
$ jstat -gcutil 692
S0S1EOMCCSYGCYGCTFGCFGCTGCT
0.0084.7384.6162.8495.9189.39490.40800.0000.408
使用表格来更好地展示与说明。
空间容量信息:
S0
:Survivor0区域空间使用百分比;S1
:Survivor1区域空间使用百分比;E
:Eden区域空间使用百分比;O
:Old区域空间使用百分比;M
:Metaspace区域空间使用百分比;CCS
:CompressedClass区域空间使用百分比;
YGC
:Young GC事件次数;YGCT
:Young GC事件所用的总时间(s);FGC
:Full GC事件次数;FGCT
:Full GC事件所用的总时间(s):GCT
:GC事件所用的总时间(s),即YGCT + FGCT;
$ jstat -gccause 692
S0S1EOMCCSYGCYGCTFGCFGCTGCTLGCCGCC
32.100.0088.3563.6095.9089.42520.43400.0000.434 Allocation FailureNo GC
主要对下面两个参数进行说明:
LGCC
:触发上一次GC的原因(Cause of last garbage collection);GCC
:触发当前GC的原因(Cause of current garbage collection);
2.3.5 -gcnew监视新生代垃圾收集状况。
$ jstat -gcnew 962
S0CS1CS0US1UTT MTTDSSECEUYGCYGCT
4352.0 4352.00.0 4352.016 2176.034944.018666.0530.502
各参数说明如下:
S0C
:Survivor0区域空间容量(kB);
S1C
:Survivor1区域空间容量(kB);
S0U
:Survivor0区域空间使用量(kB);
S1U
:Survivor1区域空间使用量(kB);
TT
:Tenuring threshold,Survivor空间中,对象的age达到该阈值的大小就会直接晋升到老年代,其为动态计算;
MTT
:Maximum tenuring threshold,Survivor空间中,TT的最大阈值大小;
DSS
:Desired survivor size (kB);
- ```c++
// TargetSurvivorRatio默认50,意思是:在回收之后希望survivor区的占用率达到这个比例
size_t desired_survivor_size = (size_t)((((double) survivor_capacity)*TargetSurvivorRatio)/100)
// 默认在Survivor空间中相同年龄所有对象大小总和大于Survivor空间的一半,年龄大于或等于该
// 年龄的对象就可以直接进入老年代。这里为什么是一半?就是因为TargetSurvivorRatio设置为
// 50,这个计算出来的空间就是Survivor的一半,可以参考后面提供的文章对JVM源码的分析。
- ```c++
EC
:Eden区域空间容量 (kB);
EU
:Eden区域空间使用量 (kB);
YGC
:Young GC事件次数;
YGCT
:Young GC事件所用的总时间(s);
$ jstat -gcold 962
MCMUCCSCCCSUOCOUYGCFGCFGCTGCT
287592.0 275461.441104.036682.1261292.0186662.16000.0000.553
各参数说明如下:
MC
: Metaspace区域空间容量(kB);MU
: Metaspace区域空间使用量(kB);CCSC
: CompressedClass区域空间使容量(kB);CCSU
: CompressedClass区域空间使用量(kB);OC
: Old区域空间容量(kB);OU
: Old区域空间使用量(kB);YGC
: Young GC事件次数;FGC
: Full GC事件次数;FGCT
: Full GC事件所用的总时间(s);GCT
: GC事件所用的总时间(s),即YGCT + FGCT;
$ jstat -compiler 962
Compiled Failed InvalidTimeFailedType FailedMethod
225364078.341 com/intellij/codeInspection/ex/InspectionProfileImpl addTool
各参数说明如下:
Compiled
: 编译次数;Failed
: 失败的编译次数;Invalid
: 无效的编译次数;Time
: 编译所消耗的总时间;FailedType
: 最后一次编译失败的编译类型;FailedMethod
: 最后一次编译失败的类名和方法;
$ jstat -printcompilation 962
CompiledSizeType Method
22575231 java/io/ObjectStreamClass$EntryFuture set
各参数说明如下:
Compiled
: 最近编译的方法执行的编译次数(描述虽然跟-compiler的不同,但实际上看数值它们其实是一样的);
Size
: 最近编译的方法的字节码的字节数;
Type
: 最近编译的方法的编译类型;
Method
: 类名和方法名标识最近编译的方法,其中类名使用/
而不是.
来分隔,方法名就是类中的方法名,这两项内容的输出格式跟虚拟机参数-XX:+PrintCompilation
是一致的;
Java配置信息工具。
jinfo [ option ] pid
主要介绍
-flag
参数,如果想查看一个已经运行的java程序的虚拟机参数值:$ jinfo -flag MaxMetaspaceSize 962
-XX:MaxMetaspaceSize=18446744073709547520
$ jinfo -flag MaxTenuringThreshold 962
-XX:MaxTenuringThreshold=6
2.4 jmap
Java内存映像工具。
jmap [ option ] vmid
各参数说明如下:
选项 | 作用 |
---|---|
-dump | 生成Java堆转储快照。格式为-dump:[live,],format=b,file=&
lt;
filename&
gt;
,其中live子参数说明是否只dump出存活的对象 |
-heap | 显示Java堆详细信息,如使用哪种回收器、参数配置、分代状况等。只在Linux/Solaris平台下有效 |
-histo | 显示堆中对象统计信息,包括类、实例数量、合计容量 |
-F | 当虚拟机进程对-dump选项没有响应时,可使用这个选项强制生成dump快照。只在Linux/Solaris平台下有效 |
2.4.1 -dump生成Java堆转储快照。
这个最常用,可以将当前java程序的堆内存dump下来,然后再做分析。
$ jmap -dump:format=b,file=idea_heap.hrpof 962
Dumping heap to /private/tmp/idea_heap.hrpof ...
Heap dump file created
$ ls -lh idea_heap.hrpof
-rw-------1 yyhwheel321M25 22:56 idea_heap.hrpof
可以看到也是有一定空间大小的,取决于当前java程序所占用的堆内存空间大小,堆内存dump下来后就可以使用MAT打开进行相应的分析了。
2.4.2 -histo显示堆中对象统计信息,包括类、实例数量、合计容量。
$ jmap -histo 962 | more
num#instances#bytesclass name (module)
-------------------------------------------------------
1:82632898417200[B (java.base@11.0.5)
2:53134612752304java.lang.String (java.base@11.0.5)
3:3611812640928[I (java.base@11.0.5)
4:16289710665248[Ljava.lang.Object;
(java.base@11.0.5)
$ jmap -histo 962 >
instances.txt
$ wc -l instances.txt
26304 instances.txt
内容也是比较多的,所以可以保存到文件中,然后再进行相应分析。
2.5 jstack
Java堆栈跟踪工具。
jstack [ option ] vimd
用于生成虚拟机当前时刻的线程快照(一般称为threaddump或者javacore文件)。线程快照就是当前虚拟机内每一条线程正在执行的方法堆栈集合,生成线程快照的目的通常是定位线程出现长时间停顿的原因,如线程间死锁、死循环、请求外部资源导致的长时间挂起等,都是导致线程长时间停顿的常见原因。
各参数说明如下:
选项 | 作用 |
---|---|
-F | 当正常输出的请求不被响应时,强制输出线程堆栈 |
-l | 除堆栈外,显示关于锁的附加信息(如果有死锁,会分析出来,非常有用) |
-m | 如果调用到本地方法的话,可以显示C/C++的堆栈 |
$ jstack -l 962 | more
2020-02-05 23:18:07
Full thread dump OpenJDK 64-Bit Server VM (11.0.5+10-b520.30 mixed mode):Threads class SMR info:
_java_thread_list=0x0000600002fdb0e0, length=42, elements=
0x00007f8b55009800, 0x00007f8b5500a800, 0x00007f8b53822800, 0x00007f8b53806000,
0x00007f8b53826000, 0x00007f8b53827000, 0x00007f8b5501f800, 0x00007f8b54009800,
0x00007f8b54003800, 0x00007f8b551c2800, 0x00007f8b53966800, 0x00007f8b54279000,
0x00007f8b53996000, 0x00007f8b5530e000, 0x00007f8b53bbe000, 0x00007f8b5445d800,
0x00007f8b53a01800, 0x00007f8b53a22000, 0x00007f8b53ced800, 0x00007f8b5811c000,
0x00007f8b57bdb000, 0x00007f8b57341000, 0x00007f8b57460000, 0x00007f8b588ee800,
0x00007f8b588f4800, 0x00007f8b541fc800, 0x00007f8b541fd800, 0x00007f8b57826800,
0x00007f8b56dd0000, 0x00007f8b62825800, 0x00007f8b5e932000, 0x00007f8b59872800,
0x00007f8b4407f000, 0x00007f8b443f5000, 0x00007f8b43d76800, 0x00007f8b44d42000,
0x00007f8b62971000, 0x00007f8b610d9000, 0x00007f8b44d48000, 0x00007f8b5f8b8000,
0x00007f8b555ec000, 0x00007f8b4436c800"Reference Handler" #2 daemon prio=10 os_prio=31 cpu=31.02ms elapsed=82877.18s tid=0x00007f8b55009800 nid=0x3803 waiting on condition[0x00007000036e3000]
java.lang.Thread.State: RUNNABLE
at java.lang.ref.Reference.waitForReferencePendingList(java.base@11.0.5/Native Method)
at java.lang.ref.Reference.processPendingReferences(java.base@11.0.5/Reference.java:241)
at java.lang.ref.Reference$ReferenceHandler.run(java.base@11.0.5/Reference.java:213)Locked ownable synchronizers:
- None
$ jstack -l 962 >
idea_stack.txt
$ wc -l idea_stack.txt
635 idea_stack.txt
2.6 jconsole
Java监视与管理控制台。
在jdk的bin目录是有jconsole的,可以直接打开,在Unix系操作系统上,直接输入jsconsole也可以直接打开。这里主要看一下其功能有哪些,因为实际上对于可视化监控,是更推荐VisualVM,jconsole本身个人用得也不多。
2.6.1 概览
文章图片
2.6.2 内存
文章图片
2.6.3 线程
文章图片
2.6.4 类
文章图片
2.6.5 VM概要
文章图片
2.6.6 MBean
文章图片
2.7 VisualVM
VisualVM是更常用的可视化监控工具,它本身还具有插件扩展功能,因此功能非常强大,目前使用非常多。
需要先说明的是一些安装上的问题,虽然安装好jdk之后是会有一个VisualVM的程序在jdk的bin目录下,但是不建议使用jdk提供的这个,建议直接去官网下载最新的版本使用。
下载:
http://visualvm.github.io/download.html
插件下载:
http://visualvm.github.io/pluginscenters.html
插件的安装这里就不做介绍了,实际上不复杂,可以查找相关资料。
下面会给出其几个比较主要的功能视图的基本情况。
2.7.1 Overview
文章图片
2.7.2 Monitor
文章图片
2.7.3 Threads
文章图片
2.4.7 Visual GC
文章图片
2.8 远程监控
2.8.1 JMX远程监控JMX的全称为Java Management Extensions,是管理Java的一种扩展。这种机制可以方便的管理正在运行中的Java程序。常用于管理线程,内存,日志Level,服务重启,系统环境等。
如果希望我们的Java程序被JMX管理,那么可以在启动Java程序时添加下面的参数:
-Dcom.sun.management.jmxremote.port=端口号
-Dcom.sun.management.jmxremote.ssl=false
-Dcom.sun.management.jmxremote.authenticate=false
-Djava.rmi.server.hostname=远程主机ip
之后打开VisualVM,进行下面的操作即可进行远程监控:
- 1.右键
Remote
,选择Add Remote Host
,填写前面配置的远程主机IP; - 2.在
Remote
的下拉列表中,选择刚刚添加的远程主机,右键,并选择Add JMX Connection
,然后在Connection
中填写前面配置的端口号即可,之后可以看到远程主机的下拉列表中有JMX监控,双击就可以打开VisualVM的监控界面;
jmx
可以很好地监控java程序,但其实也有一个问题:原来没有被监控的java程序要想被监控,则需要修改启动参数并重启服务。那有没有更好的办法呢?可以使用
jstat
,前面已经介绍过jstat
了,而jstatd
可以理解为它的服务端,在一台主机上面启动了jstatd
,我们就可以监控当前这台主机上面所有的java程序。先找到
tools.jar
的路径:$ pwd
/Library/Java/JavaVirtualMachines/jdk1.8.0_241.jdk/Contents/Home/lib
$ ls tools.jar
tools.jar
创建
jstatd
启动所需的安全策略文件:$ cat /tmp/jstatd.all.policy
grant codebase "file:/Library/Java/JavaVirtualMachines/jdk1.8.0_241.jdk/Contents/Home/lib/tools.jar"
permission java.security.AllPermission;
;
然后启动
jstatd
:$ jstatd -J-Djava.security.policy=/tmp/jstatd.all.policy -p 34893
打开
VisualVM
,执行下面的操作:- 1.右键
Remote
,选择Add Remote Host
,填写前面配置的远程主机IP; - 2.在
Remote
的下拉列表中,选择刚刚添加的远程主机,右键,并选择Add jstatd Connection
,然后在Connection
中填写前面配置的端口号即可,之后可以看到远程主机的下拉列表中有很多java进程,双击就可以打开VisualVM的监控界面,并对某一个java进程进行监控;
3.1 堆内存大小调优
3.1.1 -Xms和-Xmx即初始化堆内存大小和最大堆内存大小。
(1)-Xms
初始化的堆内存大小配置多少比较合适?可以启动你的Java程序,看稳定下来后,堆内存大小是多少,那么其实就可以设定为这个值。不建议设置得太小或者远小于程序稳定后所占的堆内存空间,因为这样会导致程序在启动时会频繁对堆内存空间进行扩容,不断申请内存,这会对启动速度造成一定影响。
也看到有一些程序会把
-Xms
和-Xmx
配置成一样大的,这样就完全避免了申请空间的影响,因为可能会存在这样一种情况:-Xmx配置为2G,程序启动后堆内存稳定在1G左右。但程序本身有可能会承受突然的并发,假设1G的堆内存空间无法处理这些并发,而2G的堆内存空间是可以处理的。
这样可能会导致一个问题,就是并发过来的时候匆忙申请堆内存空间,但实际上请求已经处理不过来了,很有可能
在申请内存空间与处理请求的同一时间,程序就因为堆内存空间不足而OOM了。当然,这只是假设有这样一种情况(实际也遇到过),生产环境上还是考虑你程序的实际场景和实现方式。
(2)-Xmx
它应该是根据你程序的实际需要而进行适当地设置,并不是越大越好的,因为即使当前堆内存大小还没有达到最大堆内存大小,这部分内存也会被JVM虚拟机锁定。
3.2 非堆内存大小调优
3.2.1 -Xss即线程栈大小。
注意这使用的是本地直接内存的空间,线程在执行时占用的主要空间是方法执行时的本地变量表,这也就意味着,当前线程压栈越多,其占用的空间也就越大,所以不能无限制地进行压栈,或者说线程栈所占用的空间不能无限地大,应该要做一定的限制,这时就可以配置
-Xss
参数。比较常见的是配置
-Xss256k
、-Xss512k
等,当然取决于你的程序,如果确定本身程序不会很复杂,调用栈也不会很深,调小一点可以节省一定的内存空间。3.2.2 -XX:MaxMetaspaceSize即最大元空间大小。
即用来保存类信息、
推荐阅读
- Nginx+keepalived实现高可用集群 #yyds干货盘点#
- 如何利用VuePress和Github Page搭建一个轻量级博客
- Nginx动静分离详解以及配置 #yyds干货盘点#
- #yyds干货盘点# JUC锁: ReentrantLock详解
- Nginx四层负载均衡详解 #yyds干货盘点#
- Shell编程之case语句与循环语句
- jenkins+kubernetes(k8s)+docker持续集成与部署(CI/CD) - k8s系列
- Nginx七层负载均衡 #yyds干货盘点#
- Linux磁盘和文件系统管理(磁盘配额的详细做法)