记录下如何监控JVM,包括JVM的线程、堆内存、CPU使用情况等
GC LOG GC日志能够反应JVM内存的动态分配回收状况、应用停顿的时间,是GC调优的依据
JVM配置查询
jmap -heap [pid]
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 Mac:dmz-inward- mac$ jmap -heap 1016 (JDK1.8) Attaching to process ID 1016, please wait... Debugger attached successfully. Server compiler detected. JVM version is 25.40-b25 using thread-local object allocation. Parallel GC with 4 thread(s) Heap Configuration: MinHeapFreeRatio = 0 MaxHeapFreeRatio = 100 MaxHeapSize = 1073741824 (1024.0MB) NewSize = 22020096 (21.0MB) MaxNewSize = 357564416 (341.0MB) OldSize = 45088768 (43.0MB) NewRatio = 2 SurvivorRatio = 8 MetaspaceSize = 21807104 (20.796875MB) CompressedClassSpaceSize = 1073741824 (1024.0MB) MaxMetaspaceSize = 17592186044415 MB G1HeapRegionSize = 0 (0.0MB) Heap Usage: PS Young Generation Eden Space: capacity = 16777216 (16.0MB) used = 11951560 (11.397895812988281MB) free = 4825656 (4.602104187011719MB) 71.23684883117676% used From Space: capacity = 3145728 (3.0MB) used = 2879968 (2.746551513671875MB) free = 265760 (0.253448486328125MB) 91.55171712239583% used To Space: capacity = 3145728 (3.0MB) used = 0 (0.0MB) free = 3145728 (3.0MB) 0.0% used PS Old Generation capacity = 45088768 (43.0MB) used = 857520 (0.8177947998046875MB) free = 44231248 (42.18220520019531MB) 1.9018483716388082% used 4674 interned Strings occupying 366808 bytes.
GC日志文件
-verbose:gc
-XX:+PrintGCDetails
-XX:+PrintGCApplicationStoppedTime
-XX:+PrintGCDateStamps
-XX:+PrintHeapAtGC , GC前后输出堆内存大小
-Xloggc:[file] , GC信息输出到独立文件中
-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=[file] ,记录 堆内存耗尽时的堆快照
-XX:ErrorFile=[file] ,记录JVM虚拟机本身的异常信息
1 -XX:+PrintGCDetails -XX:+PrintGCApplicationStoppedTime -XX:+PrintHeapAtGC -Xloggc:/tmp/gc.log -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/tmp/ -XX:ErrorFile=/tmp/JVM_Error.log
jstat
GC、堆内存信息总情况
jstat -gcutil [pid] [intervel] [count]
1 2 3 4 5 6 7 8 9 10 Mac:JDK mac$ jstat -gcutil 3157 500 2 S0 S1 E O M CCS YGC YGCT FGC FGCT GCT 0.00 0.00 52.00 97.79 66.51 69.76 3 0.022 2 0.067 0.089 0.00 0.00 52.00 95.80 66.51 69.76 3 0.022 2 0.067 0.089 S0 S1 E O M : 表示堆内存各区已使用空间的百分比 YGC FGC : 表示Young GC、Full GC 的次数 YGCT FGCT GCT : 表示YoungGC、Full GC 、GC 所用的时间 CCS : 压缩使用比例
年轻代GC情况
jstat -gcnew [pid] [intervel] [count]
1 2 3 4 5 6 7 8 9 10 11 Mac:JDK mac$ jstat -gcnew 3157 500 2 S0C S1C S0U S1U TT MTT DSS EC EU YGC YGCT 512.0 512.0 0.0 0.0 7 15 512.0 2048.0 1065.0 11 0.044 512.0 512.0 0.0 0.0 7 15 512.0 2048.0 1065.0 11 0.044 S0C S1C EC : S0、S1、E区大小(KB) S0U S1U EU : S0、S1、E区已使用大小(KB) TT : 对象在新生代存活的次数 MTT : 对象的最大年龄 DSS : 期待的Survivor区大小
年轻代内存统计
jstat -gcnewcapacity [pid]
1 2 3 4 5 6 7 Mac:JDK mac$ jstat -gcnewcapacity 3157 NGCMN NGCMX NGC S0CMX S0C S1CMX S1C ECMX EC YGC FGC 3072.0 13312.0 3072.0 4096.0 512.0 4096.0 512.0 12288.0 2048.0 15 14 NGCMN NGCMX : 年轻代最小、最大空间 NGC :当前年轻代大小
年老代
jstat -gcold [pid] [intervel] [count]
jstat -gcoldcapacity [pid]
元数据空间
jstat -gcmetacapacity [pid]
1 2 3 4 5 6 7 Mac:JDK mac$ jstat -gcmetacapacity 3157 MCMN MCMX MC CCSMN CCSMX CCSC YGC FGC FGCT GCT 0.0 1056768.0 4864.0 0.0 1048576.0 512.0 17 16 0.491 0.556 CCSMN CCSMX : 压缩类最小、最大空间 CCSC : 当前压缩类空间大小
命令行监控 命令行监控可结合脚本共同使用
jcmd 1 2 3 4 5 获取运行的JVM进程:jcmd -l 获取JVM运行的时间:jcmd process_id VM.uptime 获取系统属性:jcmd process_id VM.system_properties 获取JVM调优参数:jcmd process_id VM.flags 获取JVM线程信息:jcmd process_id Thread.print
堆快照文件 jmap用于导出堆的快照文件,便于后续分析
1 2 3 4 Mac:JDK mac$ jmap -dump:format=b,file=/Users/mac/IdeaProjects/JDK/heap.hprof 3157 Dumping heap to /Users/mac/IdeaProjects/JDK/heap.hprof ... Heap dump file created
线程栈文件 将线程栈信息导入文件 jstack [pid] > threaddump.out | jcmd [pid] Thread.print > ./threaddump.out
1 2 Mac:JDK mac$ jcmd 3157 Thread.print > ./threaddump.out
图形化监控 JDK内置有jvisualvm 、jconsole 直观的图形化监控工具
VisualVM 1 2 3 通过命令行直接唤醒启动 Mac:JDK mac$ jvisualvm
Visual GC Visual GC提供图形化的JVM堆内存使用的动态监控,由VisualVM以插件的形式提供
A magician is a man of his word. - Alfred Borden
The Prestige
事例 如何定位服务器 CPU 使用率过高的问题?可以通过如下几个步骤
获取系统进程信息
找出 CPU 使用率最高的 PID
获取指定进程的线程信息
找出 CPU 使用率最高的 PID(这里是线程 ID),并将线程 ID 转换为16进制值
查询线程信息,并定位源码位置 1 jstack 1 | grep 0x6 -A 50