美文网首页
JVM性能优化-常用工具

JVM性能优化-常用工具

作者: 奔跑地蜗牛 | 来源:发表于2019-10-16 16:57 被阅读0次

    简介

    性能优化和故障排除是一件比较麻烦的事,针对性能优化,必须得先了解相关的优化工具,然后针对不同场景不同问题选用不同工具进行分析,找出故障原因;
    jdk自带性能分析工具有:jps,jstack,jstat,jconsole,jmap和mat,visualvm;
    linux常用性能分析工具有: top ,pidstat等

    jps(jvm process status tools)

    jps是用来显示当前所有java pid的命令工具,利用它可以用来查看java进程pid,以及main方法传递的参数,main方法的包名,以及运行时jvm配置参数:

    • jps (null):jps 后面不跟任何参数表示查看当前系统中所有运行java的进程的pid;
    • jps -l:查看运行java进程的main方法的完整的pacakge名称或者jar应用文件的完整路径名称;例如:
    D:\java\jdk10\bin>jps -l
    12912
    48028 jdk.jcmd/sun.tools.jps.Jps
    
    • jps -m:查看运行java进程的main方法传递进来的参数,如果没有就为null;
    • jps -v:查看运行java进程启动配置的jvm运行时参数,例如:
    D:\java\jdk10\bin>jps -v
    12912  -Dosgi.requiredJavaVersion=1.8 -Dosgi.instance.area.default=@user.home/eclipse-workspace -XX:+UseG1GC -XX:+UseStringDeduplication -Dosgi.requiredJavaVersion=1.8 -Dosgi.dataAreaRequiresExplicitInit=true -Xms256m -Xmx1024m -Declipse.p2.max.threads=10 -Doomph.update.url=http://download.eclipse.org/oomph/updates/milestone/latest -Doomph.redirection.index.redirection=index:/->http://git.eclipse.org/c/oomph/org.eclipse.oomph.git/plain/setups/ -Dosgi.requiredJavaVersion=1.8 -Dosgi.instance.area.default=@user.home/eclipse-workspace -XX:+UseG1GC -XX:+UseStringDeduplication -Dosgi.requiredJavaVersion=1.8 -Dosgi.dataAreaRequiresExplicitInit=true -Xms256m -Xmx1024m -Declipse.p2.max.threads=10 -Doomph.update.url=http://download.eclipse.org/oomph/updates/milestone/latest -Doomph.redirection.index.redirection=index:/->http://git.eclipse.org/c/oomph/org.eclipse.oomph.git/plain/setups/
    61372 Jps -Dapplication.home=D:\java\jdk10 -Xms8m -Djdk.module.main=jdk.jcmd
    

    jstack(jvm stack tools)

    jstack是jvm自带的可以用来生成运行时线程快照的工具,通过线程快照可以得到jvm运行时每一条运行中线程的信息,一般可以用来分析线程长时间停顿的原因,如死锁,死循环,激烈的锁竞争,外部资源请求等待,如下:

    D:\java\jdk10\bin>jstack 34152
    2019-05-23 23:20:34
    Full thread dump Java HotSpot(TM) 64-Bit Server VM (11.0.2+7-LTS mixed mode):
    
    Threads class SMR info:
    _java_thread_list=0x000001fbfd43c300, length=11, elements={
    0x000001fbfc995800, 0x000001fbfc996800, 0x000001fbfd298800, 0x000001fbfd29a800,
    0x000001fbfd2a4000, 0x000001fbfd2a9000, 0x000001fbfd2c0800, 0x000001fbfd444000,
    0x000001fbfd454000, 0x000001fbfd455800, 0x000001fbd9008800
    }
    
    "Reference Handler" #2 daemon prio=10 os_prio=2 cpu=0.00ms elapsed=19.85s tid=0x000001fbfc995800 nid=0x57ac waiting on condition  [0x0000003a388ff000]
       java.lang.Thread.State: RUNNABLE
            at java.lang.ref.Reference.waitForReferencePendingList(java.base@11.0.2/Native Method)
            at java.lang.ref.Reference.processPendingReferences(java.base@11.0.2/Reference.java:241)
            at java.lang.ref.Reference$ReferenceHandler.run(java.base@11.0.2/Reference.java:213)
    
    "Finalizer" #3 daemon prio=8 os_prio=1 cpu=0.00ms elapsed=19.85s tid=0x000001fbfc996800 nid=0x194e0 in Object.wait()  [0x0000003a389ff000]
       java.lang.Thread.State: WAITING (on object monitor)
            at java.lang.Object.wait(java.base@11.0.2/Native Method)
            - waiting on <0x0000000710d08f10> (a java.lang.ref.ReferenceQueue$Lock)
            at java.lang.ref.ReferenceQueue.remove(java.base@11.0.2/ReferenceQueue.java:155)
            - waiting to re-lock in wait() <0x0000000710d08f10> (a java.lang.ref.ReferenceQueue$Lock)
            at java.lang.ref.ReferenceQueue.remove(java.base@11.0.2/ReferenceQueue.java:176)
            at java.lang.ref.Finalizer$FinalizerThread.run(java.base@11.0.2/Finalizer.java:170)
    
    "Signal Dispatcher" #4 daemon prio=9 os_prio=2 cpu=0.00ms elapsed=19.82s tid=0x000001fbfd298800 nid=0x1364c runnable  [0x0000000000000000]
       java.lang.Thread.State: RUNNABLE
    
    "Attach Listener" #5 daemon prio=5 os_prio=2 cpu=0.00ms elapsed=19.82s tid=0x000001fbfd29a800 nid=0x1fc0 waiting on condition  [0x0000000000000000]
       java.lang.Thread.State: RUNNABLE
    
    "C2 CompilerThread0" #6 daemon prio=9 os_prio=2 cpu=15.63ms elapsed=19.82s tid=0x000001fbfd2a4000 nid=0x11f28 waiting on condition  [0x0000000000000000]
       java.lang.Thread.State: RUNNABLE
       No compile task
    
    "C1 CompilerThread0" #9 daemon prio=9 os_prio=2 cpu=31.25ms elapsed=19.82s tid=0x000001fbfd2a9000 nid=0xf1bc waiting on condition  [0x0000000000000000]
       java.lang.Thread.State: RUNNABLE
       No compile task
    
    "Sweeper thread" #10 daemon prio=9 os_prio=2 cpu=0.00ms elapsed=19.82s tid=0x000001fbfd2c0800 nid=0xcb58 runnable  [0x0000000000000000]
       java.lang.Thread.State: RUNNABLE
    
    "Service Thread" #11 daemon prio=9 os_prio=0 cpu=0.00ms elapsed=19.78s tid=0x000001fbfd444000 nid=0xe398 runnable  [0x0000000000000000]
       java.lang.Thread.State: RUNNABLE
    
    "Common-Cleaner" #12 daemon prio=8 os_prio=1 cpu=0.00ms elapsed=19.78s tid=0x000001fbfd454000 nid=0xeb30 in Object.wait()  [0x0000003a391ff000]
       java.lang.Thread.State: TIMED_WAITING (on object monitor)
            at java.lang.Object.wait(java.base@11.0.2/Native Method)
            - waiting on <0x0000000710c5ad28> (a java.lang.ref.ReferenceQueue$Lock)
            at java.lang.ref.ReferenceQueue.remove(java.base@11.0.2/ReferenceQueue.java:155)
            - waiting to re-lock in wait() <0x0000000710c5ad28> (a java.lang.ref.ReferenceQueue$Lock)
            at jdk.internal.ref.CleanerImpl.run(java.base@11.0.2/CleanerImpl.java:148)
            at java.lang.Thread.run(java.base@11.0.2/Thread.java:834)
            at jdk.internal.misc.InnocuousThread.run(java.base@11.0.2/InnocuousThread.java:134)
    
    "test" #13 prio=5 os_prio=0 cpu=19734.38ms elapsed=19.77s tid=0x000001fbfd455800 nid=0x63d8 runnable  [0x0000003a392ff000]
       java.lang.Thread.State: RUNNABLE
            at jvm.optimize.TestOptimize$1.run(TestOptimize.java:11)
    
    "DestroyJavaVM" #14 prio=5 os_prio=0 cpu=125.00ms elapsed=19.77s tid=0x000001fbd9008800 nid=0xb574 waiting on condition  [0x0000000000000000]
       java.lang.Thread.State: RUNNABLE
    
    "VM Thread" os_prio=2 cpu=0.00ms elapsed=19.86s tid=0x000001fbfc983000 nid=0x6270 runnable
    
    "GC Thread#0" os_prio=2 cpu=0.00ms elapsed=19.89s tid=0x000001fbd901d800 nid=0x104fc runnable
    
    "G1 Main Marker" os_prio=2 cpu=0.00ms elapsed=19.89s tid=0x000001fbd907b800 nid=0x9d20 runnable
    
    "G1 Conc#0" os_prio=2 cpu=0.00ms elapsed=19.89s tid=0x000001fbd907e000 nid=0x1174c runnable
    
    "G1 Refine#0" os_prio=2 cpu=0.00ms elapsed=19.88s tid=0x000001fbfc861800 nid=0xa648 runnable
    
    "G1 Young RemSet Sampling" os_prio=2 cpu=0.00ms elapsed=19.88s tid=0x000001fbfc865000 nid=0xe880 runnable
    "VM Periodic Task Thread" os_prio=2 cpu=0.00ms elapsed=19.78s tid=0x000001fbfd44b000 nid=0x10dc0 waiting on condition
    
    JNI global refs: 6, weak refs: 0
    

    jstat

    jstat是用来对基于Hotspot的jvm,对其堆的使用情况进行实时检测,如:

    • 类的加载与卸载情况;
    • 查看新生代,老年代,持久代堆内存容量及使用情况;
    • 查看新生代,老年代,持久代垃圾回收情况,包括回收次数,每次回收消耗时间等;
    • 查看新生代Eden区以及Survivor区分区情况;

    例如:

    D:\java\jdk10\bin>jstat -gc 68748
    
     S0C    S1C    S0U    S1U      EC       EU        OC         OU       MC     MU    CCSC   CCSU   YGC     YGCT    FGC    FGCT     GCT
    10752.0 10752.0  0.0    0.0   65536.0   7864.9   175104.0     0.0     4480.0 751.8  384.0   76.4       0    0.000   0      0.000    0.000
    

    如上所示,各指标信息如下:

    • S0C:表示Survivor 0区容量大小(字节)
    • S1C:表示Survivor 1区容量大小(字节);
    • S0U:表示Survivor 0区使用的容量大小;
    • S1U:表示Survivor 1区使用的容量大小;
    • EC:表示Eden区容量大小;
    • EU:表示Eden区使用容量大小;
    • OC:表示老年代容量大小;
    • OU:表示老年代使用容量大小;
    • MC:表示元数据区容量大小(JDK8以后出现的);
    • MU:表示元数据区使用大小;
    • CCSC:表示压缩类空间容量大小 (Compress Class Space Capacity);
    • CCSU:表示压缩类空间使用大小;
    • YGC:年轻代垃圾回收次数(Young GC Count);
    • YGCT:年轻代垃圾回收消耗时间(Young GC Time);
    • FGC:full gc垃圾回收次数;
    • FGCT :full gc垃圾回收消耗时间(秒);
    • GCT: GC TIMe,即垃圾回收消耗总时间=FGCT+YGCT;

    jmap,mat,jhprof

    jmap是用来打印或者导出某个jvm进程内所有对象(存活的或者死亡还未回收的);
    jmap使用方法如下:

    • jmap -heap pid:查看该进程下堆内存使用情况;
    Heap Configuration:
       MinHeapFreeRatio         = 0//对应jvm启动参数-XX:MinHeapFreeRatio设置JVM堆最小空闲比率(default 40)
       MaxHeapFreeRatio         = 100//对应jvm启动参数 -XX:MaxHeapFreeRatio设置JVM堆最大空闲比率(default 70)
       MaxHeapSize              = 4183818240 (3990.0MB)//对应jvm启动参数-XX:MaxHeapSize=设置JVM堆的最大大小
       NewSize                  = 87031808 (83.0MB) //对应jvm启动参数-XX:NewSize=设置JVM堆的‘新生代’的默认大小
       MaxNewSize               = 1394606080 (1330.0MB) //对应jvm启动参数-XX:MaxNewSize=设置JVM堆的‘新生代’的最大大小
       OldSize                  = 175112192 (167.0MB) //对应jvm启动参数-XX:OldSize=<value>:设置JVM堆的‘老生代’的大小
       NewRatio                 = 2//对应jvm启动参数-XX:NewRatio=:‘新生代’和‘老生代’的大小比率
       SurvivorRatio            = 8//对应jvm启动参数-XX:SurvivorRatio=设置年轻代中Eden区与Survivor区的大小比值
       MetaspaceSize            = 21807104 (20.796875MB) //对应jvm启动参数-XX:PermSize=<value>:设置JVM堆的‘永生代’的初始大小
       CompressedClassSpaceSize = 1073741824 (1024.0MB)
       MaxMetaspaceSize         = 17592186044415 MB//对应jvm启动参数-XX:MaxPermSize=<value>:设置JVM堆的‘永生代’的最大大小
       G1HeapRegionSize         = 0 (0.0MB)
    
    Heap Usage://堆内存使用情况
    PS Young Generation//年轻代
    Eden Space://Eden区空间使用情况
       capacity = 340787200 (325.0MB)
       used     = 306906696 (292.6890335083008MB)
       free     = 33880504 (32.31096649169922MB)
       90.05816415640024% used
    From Space://From Survivor区的内存使用情况
       capacity = 524288 (0.5MB)
       used     = 491520 (0.46875MB)
       free     = 32768 (0.03125MB)
       93.75% used
    To Space://To Survivor区内存使用情况
       capacity = 19922944 (19.0MB)
       used     = 0 (0.0MB)
       free     = 19922944 (19.0MB)
       0.0% used
    PS Old Generation //老年代内存使用情况
       capacity = 219676672 (209.5MB)
       used     = 40968392 (39.07050323486328MB)
       free     = 178708280 (170.42949676513672MB)
       18.649404885376267% used
    
    • jmap -histo:live pid :查看指定进程下存活对象信息,可用于定位内存泄漏;
    • jmap -histo:live pid >1.txt将信息输出到指定文件中

    mat:是Eclipse的内存插件,可以用来查找内存泄漏和减少内存消耗;

    jinfo

    jinfo用于打印指定Java进程、核心文件或远程调试服务器的Java配置信息。配置信息包括Java系统属性、Java虚拟机命令行标识参数。

    D:\java\jdk10\bin>jinfo 68748
    Java System Properties:
    #Fri May 24 01:03:18 CST 2019
    java.runtime.name=Java(TM) SE Runtime Environment
    sun.boot.library.path=D\:\\java\\jre1.8\\bin
    java.vm.version=25.211-b12
    java.vm.vendor=Oracle Corporation
    java.vendor.url=http\://java.oracle.com/
    path.separator=;
    java.vm.name=Java HotSpot(TM) 64-Bit Server VM
    file.encoding.pkg=sun.io
    user.script=
    user.country=CN
    sun.java.launcher=SUN_STANDARD
    sun.os.patch.level=
    java.vm.specification.name=Java Virtual Machine Specification
    user.dir=D\:\\jar files
    java.runtime.version=1.8.0_211-b12
    java.awt.graphicsenv=sun.awt.Win32GraphicsEnvironment
    java.endorsed.dirs=D\:\\java\\jre1.8\\lib\\endorsed
    os.arch=amd64
    java.io.tmpdir=C\:\\Users\\ADMINI~1\\AppData\\Local\\Temp\\
    line.separator=\r\n
    java.vm.specification.vendor=Oracle Corporation
    user.variant=
    os.name=Windows 10
    sun.jnu.encoding=GBK
    java.library.path=C\:\\Program Files (x86)\\Common Files\\Oracle\\Java\\javapath;C\:\\WINDOWS\\Sun\\Java\\bin;C\:\\WINDOWS\\system32;C\:\\WINDOWS;D\:\\dev tools\\apache-maven-3.6.1\\bin\\;C\:\\Program Files (x86)\\Common Files\\Oracle\\Java\\javapath;D\:\\Python37;D\:\\Python37\\Scripts;C\:\\Program Files (x86)\\NetSarang\\Xshell 6\\;D\:\\java\\jdk-11.0.2\\bin;C\:\\Windows\\system32;C\:\\Windows;C\:\\Windows\\System32\\Wbem;C\:\\Windows\\System32\\WindowsPowerShell\\v1.0\\;C\:\\Program Files (x86)\\NVIDIA Corporation\\PhysX\\Common;C\:\\WINDOWS\\system32;C\:\\WINDOWS;C\:\\WINDOWS\\System32\\Wbem;C\:\\WINDOWS\\System32\\WindowsPowerShell\\v1.0\\;C\:\\WINDOWS\\System32\\OpenSSH\\;C\:\\Program Files\\Git\\cmd;C\:\\Program Files\\NVIDIA Corporation\\NVIDIA NvDLISR;C\:\\Go\\bin;D\:\\Program Files\\nodejs;D\:\\Program Files\\nodejs\\node_global;D\:\\Thrift;D\:\\protobuf\\protoc-3.4.0-win32\\bin;D\:\\apache-ant-1.10.6\\bin;D\:\\hadoop-3.1.2\\bin;D\:\\hadoop-3.1.2\\sbin;C\:\\Users\\Administrator\\AppData\\Local\\Microsoft\\WindowsApps;C\:\\Users\\Administrator\\AppData\\Roaming\\npm;.
    java.specification.name=Java Platform API Specification
    java.class.version=52.0
    sun.management.compiler=HotSpot 64-Bit Tiered Compilers
    os.version=10.0
    user.home=C\:\\Users\\Administrator
    user.timezone=
    java.awt.printerjob=sun.awt.windows.WPrinterJob
    file.encoding=GBK
    java.specification.version=1.8
    java.class.path=testjvm.jar
    user.name=Administrator
    java.vm.specification.version=1.8
    sun.java.command=testjvm.jar
    java.home=D\:\\java\\jre1.8
    sun.arch.data.model=64
    user.language=zh
    java.specification.vendor=Oracle Corporation
    awt.toolkit=sun.awt.windows.WToolkit
    java.vm.info=mixed mode
    java.version=1.8.0_211
    java.ext.dirs=D\:\\java\\jre1.8\\lib\\ext;C\:\\WINDOWS\\Sun\\Java\\lib\\ext
    sun.boot.class.path=D\:\\java\\jre1.8\\lib\\resources.jar;D\:\\java\\jre1.8\\lib\\rt.jar;D\:\\java\\jre1.8\\lib\\sunrsasign.jar;D\:\\java\\jre1.8\\lib\\jsse.jar;D\:\\java\\jre1.8\\lib\\jce.jar;D\:\\java\\jre1.8\\lib\\charsets.jar;D\:\\java\\jre1.8\\lib\\jfr.jar;D\:\\java\\jre1.8\\classes
    java.vendor=Oracle Corporation
    sun.stderr.encoding=ms936
    file.separator=\\
    java.vendor.url.bug=http\://bugreport.sun.com/bugreport/
    sun.io.unicode.encoding=UnicodeLittle
    sun.cpu.endian=little
    sun.stdout.encoding=ms936
    sun.desktop=windows
    sun.cpu.isalist=amd64
    
    VM Flags:
    -XX:CICompilerCount=4 -XX:InitialHeapSize=268435456 -XX:MaxHeapSize=4280287232 -XX:MaxNewSize=1426587648 -XX:MinHeapDeltaBytes=524288 -XX:NewSize=89128960 -XX:OldSize=179306496 -XX:+UseCompressedClassPointers -XX:+UseCompressedOops -XX:+UseFastUnorderedTimeStamps -XX:-UseLargePagesIndividualAllocation -XX:+UseParallelGC
    
    VM Arguments:
    java_command: testjvm.jar
    java_class_path (initial): testjvm.jar
    Launcher Type: SUN_STANDARD
    

    jconsole

    jconsole使用java gui编写的图形界面可用于展示监视的java服务器,功能很强大,可以可视化的参看java服务器运行时线程,对象,内存等,如下图:


    图片.png

    jhat(jvm heap analysis tool)

    jhat是虚拟机堆转储快照分析工具,用于分析heapdump文件,可以建立http连接,让用户在浏览器上对堆进行分析;相对mat来说,jhat没有图形那么直观;
    使用方法如下参考

    • 导出堆,如:jmap -dump:live,file=b.bin 81301
    • 分析堆,如:jhat test.bin
    • 查看堆,如:http://xxx.xxx:7000/

    jcmd

    jcmd功能很强大,可以用来导出堆,查看堆,导出线程,查看线程,查看进程信息,执行GC等;

    查看java进程:

    D:\java\jdk10\bin>jcmd
    74512 jdk.jconsole/sun.tools.jconsole.JConsole
    50184 jdk.jcmd/sun.tools.jcmd.JCmd
    68748 testjvm.jar
    

    可以使用help:

    D:\java\jdk10\bin>jcmd 68748 help
    68748:
    The following commands are available:
    JFR.stop
    JFR.start
    JFR.dump
    JFR.check
    VM.native_memory
    VM.check_commercial_features
    VM.unlock_commercial_features
    ManagementAgent.stop
    ManagementAgent.start_local
    ManagementAgent.start
    VM.classloader_stats
    GC.rotate_log
    Thread.print
    GC.class_stats
    GC.class_histogram
    GC.heap_dump
    GC.finalizer_info
    GC.heap_info
    GC.run_finalization
    GC.run
    VM.uptime
    VM.dynlibs
    VM.flags
    VM.system_properties
    VM.command_line
    VM.version
    help
    

    通过help,可以看到能进行哪些操作,例如查看VM运行时间:

    D:\java\jdk10\bin>jcmd 68748 VM.uptime
    68748:
    5334.977 s
    

    JvisualVM(可视化vm分析工具)

    该工具非常强大,可以以图形的方式对vm对象进行展示,快速分析,以及生成海量监控数据,并且可以分析GC趋势等等;
    具体可以参考这篇文章:JvisualVM使用jp

    相关文章

      网友评论

          本文标题:JVM性能优化-常用工具

          本文链接:https://www.haomeiwen.com/subject/txdizqtx.html