zoukankan      html  css  js  c++  java
  • Java应用调优指南之-工具篇

    1. 土法调优两大件

    先忆苦思甜,一般人在没有Profile工具的时候,调优的两大件,无非Heap Dump 与 Thread Dump。

     

    1.1 Heap Dump

     

    jmap -dump:live,format=b,file=heap.hprof pid

    从安全点的日志看,从Heap Dump开始,整个JVM都是停顿的,考虑到IO(写到Page Cache,或许触发background flush),几G的Heap可能产生几秒的停顿,在生产环境上执行时谨慎再谨慎。

    live的选项,实际上是产生一次Full GC来保证只看还存活的对象。有时候也会故意不加live选项,看历史对象。

    Dump出来的文件建议用JDK自带的VisualVM或Eclipse的MAT插件打开,对象的大小有两种统计方式:

    • 本身大小(Shallow Size):对象本来的大小。
    • 保留大小(Retained Size): 当前对象大小 + 当前对象直接或间接引用到的对象的大小总和。

    看本身大小时,占大头的都是char[] ,byte[]之类的,没什么意思(用jmap -histo:live pid 看的也是本身大小)。所以需要关心的是保留大小比较大的对象,看谁在引用这些char[], byte[]。

    (MAT能看的信息更多,但VisualVM胜在JVM自带,用法如下:命令行输入jvisualvm,文件->装入->堆Dump->检查 -> 查找20保留大小最大的对象,就会触发保留大小的计算,然后就可以类视图里浏览,按保留大小排序了)
     

    1.2 Thread Dump

    ThreadDump 同样会造成JVM停顿,在生产系统上执行要谨慎。

    可以命令行方式执行它,"jstack pid” 或"jstack -l pid" ,其中-l 会同时打印各种lock,但会使得JVM停顿得长久得多(可能会差一百倍,比如普通的jstack可能几毫秒和一次GC没区别,加了-l 就是近一秒的时间),慎用再慎用。

    另一种是直接用代码来打印,比如线程池满了无法添加新任务,在开发或性能测试模式下,可以在代码里捕捉该异常后直接把当前线程池的情况打印出来。

     

    ThreadMXBean threadMBean = ManagementFactory.getThreadMXBean();
    ThreadInfo[] threadInfos = threadMBean.dumpAllThreads(false, false);

    同样注意,这里threadMBean.dumpAllThreads(false,false)的参数为false,把参数改为true,则打印synchronizers与monitor,同样使得JVM停顿久很多。

    线程状态:

    • RUNNABLE: 运行中状态,可能里面还能看到locked字样,表明它获得了某把锁。
    • BLOCKED:被某个锁(synchronizers)給block住了。
    • WAITING:等待某个condition或monitor发生,一般停留在park(), wait(), sleep(),join() 等语句里。
    • TIME_WAITING:和WAITING的区别是wait() 等语句加上了时间限制 wait(timeout)。

    分析工具:

     

    2. 你真正要的Java Mission Control

    如果你使用过JProfiler,Yourkit,VisualVM还有Eclipse的Profiler插件等一堆Profiler工具,或者用JavaSimion等在代码里打印过metrics,最后会发现免费的JMC才是你想要的。
     

    2.1 优点

    代替收费的JProfiler的好东西,以前Bea JRockit的宝贝,现在随着JDK7 up40以后的版本免费自带了,不过只在开发环境免费,就是说理论上不能拿它来连生产环境的机器。

    另一个让人开心的事情就是JMC采用采样,而不是传统的代码植入的技术,对应用性能的影响非常非常小,完全可以开着JMC来做压测。不会像以前,开了代码植入型的Profiler,出来的性能测试结果差了一个数量级不说,热点完全可能是错误的,这是一个真实的故事,具体细节就不说了。
     

    2.2 功能

    JMC里可以看的东西太多了,自己觉得最有用的如下:

    • 内存Tab:分配Tab里的按类、按线程、对象的创建调用栈来归类的对象创建情况,让对象创建无处躲藏。
    • 内存Tab:GC Tab的GC详细情况,以及分配Tab中TLAB外的分配情况(每条线程在Heap里分了一个Thread Local Area,在TLAB里的内存分配不需要线程竞争,所以TLAB之外的分配是不好的)
    • 代码Tab:热点方法类及它的调用栈,超有用的功能。调用树是从线程角度看的方法调用,而按包名分类可以看3PP包的问题。
    • 线程Tab:热点线程,再换个姿势来看热点方法和调用树。
    • 线程Tab:争用,等待时间,锁定实例等。

     

    2.3 使用方法简述

    JDK7在启动服务时加上-XX:+UnlockCommercialFeatures -XX:+FlightRecorder ,JDK8则不需要。
    如果是远程服务器,要开JMX:

     

    “-Dcom.sun.management.jmxremote.port=7001 -Dcom.sun.management.jmxremote -Dcom.sun.management.jmxremote.authenticate=false -Dcom.sun.management.jmxremote.ssl=false -Djava.rmi.server.hostname=127.0.0.1”

    JDK自带的jmc命令,文件->连接->设定JMX连接,启动飞行纪录,固定时间选1分钟或更多,事件设置选为profiling,然后进一步修改,自己查看下都Profile了哪些信息,觉得不够的再添加些(下次就直接用上次设定就好了),比如:

    • 加上对象数量的统计:Java Virtual Machine->GC->Detail->Object Count/Object Count after GC
    • 方法调用采样的间隔从10ms改为1ms(但不能低于1ms,否则会影响性能了): Java Virtual Machine->Profiling下的两个选项
    • Socket与File采样的间隔从10ms改为1ms(默认的10ms会捕捉不到IO): Java Application->File Read/FileWrite/Socket Read/Socket Write

    然后就开始Profile,到时间后Profile结束,会自动把记录下载回来,在JMC中展示。

    其他资料:





  • 相关阅读:
    在TreeView控件节点中显示图片
    PAT 甲级 1146 Topological Order (25 分)
    PAT 甲级 1146 Topological Order (25 分)
    PAT 甲级 1145 Hashing
    PAT 甲级 1145 Hashing
    PAT 甲级 1144 The Missing Number (20 分)
    PAT 甲级 1144 The Missing Number (20 分)
    PAT 甲级 1151 LCA in a Binary Tree (30 分)
    PAT 甲级 1151 LCA in a Binary Tree (30 分)
    PAT 甲级 1149 Dangerous Goods Packaging
  • 原文地址:https://www.cnblogs.com/doit8791/p/5447493.html
Copyright © 2011-2022 走看看