java dump分析工具_Java 性能分析工具 (2):Java 内置监控工具

cc8d51e5daf3623311938a5f5e98de78.png

引言

本文为 Java 性能分析工具系列文章第二篇,第一篇:操作系统工具。在本文中将介绍如何使用 Java 内置监控工具更加深入的了解 Java 应用程序和 JVM 本身。在 JDK 中有许多内置的工具,其中包括:

  • jcmd:打印一个 Java 进程的类,线程以及虚拟机信息。适合用在脚本中。使用 jcmd - h 来查看使用方法。
  • jconsole:提供 JVM 活动的图形化展示,包括线程使用,类使用以及垃圾回收(GC)信息。
  • jhat:帮助分析内存堆存储。
  • jmap:提供 JVM 内存使用信息,适用于脚本中。
  • jinfo:访问 JVM 系统属性,同时可以动态修改这些属性。
  • jstack:提供 Java 进程内的线程堆栈信息。
  • jstat:提供 Java 垃圾回收以及类加载信息。
  • jvisualvm:监控 JVM 的可视化工具,剖析运行中的应用程序,分析 JVM 堆存储。

下面将根据功能划分来详细介绍这些工具。

VM 基本信息

JVM 工具能够提供一个运行中的 JVM 进程的基本信息,例如运行时间、使用中的 JVM 参数以及 JVM 系统属性。

  • uptimeJVM 运行的时间,jcmd process_id VM.uptime
  • system properties通过 System.getProperties() 可以得到的系统属性也可以通过下面的命令获得:

jcmd process_id VM.system_properties 或者 jinfo –sysprops process_id

这些属性包括所有通过命令行-D 选项设置的属性、应用程序动态添加的属性和 JVM 的默认属性。

  • JVM version通过 jcmd process_id VM.version 获得。
  • JVM command lineJVM 命令行可以在 jconsole 中的 VM summary 中找到,或者通过 jcmd process_id VM.command_line 命令获得。
  • JVM 调优参数通过命令 jcmd process_id VM.flags [-all] 命令或者所有生效的调优参数获得。

使用调优参数(Tuning Flags)

由于调优参数非常繁多,需要借助 JVM 命令行和 JVM 调优参数来使用。使用 command_line 命令可以获得命令行中指定的调优参数,flags 命令可以获得通过命令设置的调优参数和 JVM 设置的调优参数。

通过 jcmd 命令可以获得一个运行中 JVM 内生效的调优参数。通过下面这条命令可以获得一个指定平台内生效的调优参数。

java 

我们需要把其他选项同时包含在这条命令中,尤其是设置了 GC 相关的调优参数。这条命令的部分输出如下所示,第一行中的冒号说明第一行的调优参数使用的不是默认值,而是以下三种方式设置:

  1. 通过命令行设置其他选项间接改变了此调优参数的值
  2. JVM 计算出默认值第二行由于没有包含冒号,说明此行的调优参数为当前 JVM 版本的默认值,最后一列的 product 说明此行的调优参数的值在不同平台相同,而 pd product 说明此行的调优参数的值依赖于平台。
uintx 

最后一列的其他选项:

manageable

jinfo 命令可以查看某个单一 flag 的值,通过下面的命令:

jinfo 

3.通过下面的命令可以设置某个 flag 的 manageable 属性来控制其能否在运行时被改变:

jinfo 

尽管 jinfo 命令可以改变任何 flag 的值,但不能确定 JVM 会接受这些改变。例如很多影响垃圾回收算法执行的 flag 都会在 JVM 启动时被设置,在 JVM 运行过程中通过 jinfo 命令修改 flag 的值并不会影响算法执行。所有此命令只对那些 manageable 为真的 flag 起作用。

线程信息

jconsole 和 jvisualvm 命令可以帮助开发人员剖析应用程序运行过程中线程的相关信息。通过 jstack process_id 命令可以查看线程的运行时栈信息,可以明确获得当前线程是否被阻塞。通过命令 jcmd process_id Thread.print 可以获得相同结果。

类信息

通过 jconsole 和 jstat 命令可以获得应用程序运行过程中的所有类的相关信息,同时 jstat 命令也提供了类编译的相关信息。

垃圾回收信息

Jconsole 展示了 JVM 堆使用的情况,它所绘制的的动态图能够帮助开发人员了解堆的内部情况。jcmd 支持垃圾回收操作。jmap 提供堆信息总览。jstat 从不同的角度展示垃圾回收是如何工作的。

Heap Dump 文件的后序处理

通过 jvisualvm 用户界面可以得到 Heap Dump 文件,通过 jcmd 和 jmap 也可以获得。Heap Dump 文件是堆的快照,一般使用 jvisualvm 和 jhat 来分析这个快照。

性能分析工具

Java 提供的性能分析器是最重要的分析工具。它的种类繁多,各有所长,使用不同的分析器在分析同一个应用时可能会发现不同的问题。在使用过程中需要各取所长,这样才能对应用进行全面的分析。

基本上所有的 Java 性能分析器都是用 Java 实现的,通过套接字(socket)与被分析应用进行通信来获得被分析应用的运行信息。需要注意的是,在使用性能分析工具调优被分析应用的同时,需要关注性能分析器其自身的性能。假如当被分析的应用程序产生十分庞大的信息,而将其发送至性能分析器时,如果性能分析器没有空间充分管理高效的内存堆来处理这些信息时,分析将无法进行。采用并行垃圾回收算法进行内存管理是当前性能分析器比较流行的做法,这种算法能够最大程度地降低内存溢出的可能。

性能分析分为采样模式和检测模式。下面将分别介绍这两种模式。

采样分析

采样模式是性能分析中最常用的模式,因为其对被分析应用程序影响最小,这一点非常重要。只有当性能分析过程对应用程序的影响降到最低,才能获得有价值的性能分析结果。

在采样分析模式中,分析器被定时触发工作。在工作周期内,分析器依次检查每个线程并记录线程中正在运行的方法,在某些特定场景下,采样分析往往会带来错误的分析结果。例如,在图 1 中,某线程在一段时间内交替执行方法 A 和方法 B,每次当分析器被触发工作时,该线程都恰好在执行方法 B,那么分析器会认为该线程的所有时间都是在执行方法 B,但是事实并非如此,该线程执行方法 A 的时间远大于执行方法 B 的时间,只是并未被分析器采样到。

图 1. 某一时间段内线程交替执行方法 A 和 B 示例图

bcd4839162828ca50cd25fdd0b7a1ac7.png

这是采样模式中最常见的错误,通过增加采样分析器的采样时间隔可以帮助我们有效的减少这类错误的发生,因为时间间隔太小往往会增加采样分析器对被分析的应用程序产生性能方面的影响,从而导致分析结果失真。所以时间间隔需要根据被分析应用的特点通过多次的试验以及经验来决定,权衡过大或过小的影响之后设定。

图 2. 采样模式分析示例图

ee3f0943b95760854c81693ad90e040c.png

图 2 所示是使用采样模式分析一个应用服务器 GlassFish 启动过程的结果。从图中可以看到,方法 defineClass1() 使用了 19%的时间,接下来是方法 getPackageSourceInternal(),占用了 10%的时间。Java 应用程序中定义的类会影响应用程序启动过程中的性能表现,为了提高应用程序的启动速度,就必须通过提高类加载的速度,从而达到提升启动速度的目标。从图中我们可能会错误的认为要改善性能的方法是 defineClass1(),但是 defineClass1() 其实是 JDK 中的方法,我们不可能通过重写 JVM 来提高它的性能。即使重写此方法将其执行时间优化至原有时间的 60%,也只能减少 10%应用程序整体运行时间,这显然得不偿失。

检测分析

相比于采样模式,检测模式是要侵入被分析的应用程序内部,虽然这样做并不是高效、友好的,但它却可以获得非常有价值的信息。图 3 为使用相同分析工具的检测模式分析相同应用服务器 GlassFish 的结果。

图 3. 检测分析示例图

cec105ceecc1a0021a7f36d2b21c12f8.png

在图中有以下几点信息:

  1. 最耗时的方法为 getPackageSourcesInternal(), 占用了 13%的时间,而并非在采样模式中得到的 4%;
  2. 方法 defineClaass1() 并未出现在分析结果中。
  3. 分析结果中包括每个方法执行的次数和平均耗时。

这些分析结果中的信息对于发现耗时多的代码是非常有帮助的。在本例中,尽管方法 ImmutableMap.get() 消耗 12%的时间,但是它被调用了四百七十万次之多。如果减少此方法的调用次数,应用的性能将会得到大幅度提升。

检测分析器在类被加载时通过改变其字节码顺序来获取应用运行数据,例如增加记录方法被调用次数的代码。相比于采样模式,这种方式会更大程度的影响应用本身的性能。例如,JVM 会根据方法的代码块大小,将方法体很小的方法内联化,这样在内联方法执行时就不会进行方法调用。在检测分析器在内联方法中加入其代码后,此方法因为方法体过大并未被 JVM 内联化,由此造成此方法的耗时被放大。内联化只是一个例子,当越来越多的代码被改变的时候,分析的结果失真的概率就会比较大。

造成方法 ImmutableMap.get() 没有出现在采样模式分析结果中的原因是安全点(safepoint)的存在。只有当一个线程获得的内存大于安全点时,采样分析器才会对其进行分析。因为方法 ImmutableMap.get() 所在线程一直没有达到安全点,所以在结果中不会出现。当使用采样模式安全点过高时,会低估一些方法对性能的影响。

在本例中,无论是采样分析还是检测分析,都能发现应用的性能瓶颈在于类的加载和解析。但是在实际中,不同的分析器不可能得出完全相同的分析结果。分析器擅长估量,但也只是估量,一些误差甚至是错误不可避免,所以在性能分析过程中还需要我们更加灵活的使用分析器。

阻塞方法和线程的时间轴

如图 4 所示为使用 NetBeans Profiler(另一种检测分析器)分析上述应用服务器 GlassFish 启动过程的结果展示。在此结果中,方法 park(),parkNanos() 和 read() 占用了绝大多数的应用运行时间。这些方法都是被阻塞的方法,并不消耗 CPU,所以在计算应用的 CPU 使用率时这些时间不应计入。应用中的线程并没有使用 632 秒来执行 parkNanos() 方法,而是等待其他操作完成花费 632 秒。park() 和 read() 方法与此同理。

图 4. NetBeans 检测分析示例图

948413e806f88a8a09c989f1f129cf60.png

因此,大多数的分析器都不会将被阻塞的方法和闲置的线程计入结果。在 NetBeans 中,可以设置分析结果包含所有的方法,所以在本例中这些方法被计入结果。在本例中,执行 park() 方法的线程位于服务器线程池中,当服务器接收到请求时,这些线程处理请求。当没有请求时,这些线程处于阻塞状态,等到新的请求,并不占用 CPU。这是应用服务器的正常状态。

绝大多数的基于 Java 的分析器都可以提供过滤器功能来查看或者隐藏被阻塞方法调用的时间,如果需要可以使用该功能。通常情况下,查看线程的运行状况比查看被阻塞方法的阻塞时间更加有帮助。

图 5. Oracle Solaris Studio 中线程的运行示例图

e2f7712dc1ea6b79bc346ad4de4c9f62.png

图 5 为在 Oracle Solaris Studio 中一个线程的运行情况。每一个水平区域代表一个不同的线程,所以上图中有两个线程(1.3 和 1.2)。不同颜色的柱子代表执行的不同方法;空白处代表该线程没有执行任何方法。综合来看,线程 1.2 先执行了一段代码然后等待线程 1.3 完成执行,线程 1.3 完成执行后等待线程 1.2 执行另一段代码。深入下去可以发现这些线程如何进行交互。

图中存在一些没有线程执行的空白区域,这是因为图中只展示了其中的两个线程,所以在那段空白区域是图中所示两个线程在等待其他线程执行完成。

本地分析器

本地分析器是用来分析 JVM 本身的工具。通过本地分析器可以观察到 JVM 正在进行的操作或者查看是否有应用程序包含了 JVM 的本地库,也可以观察到代码内部。任何本地分析器都可以分析使用 C 语言实现的 JVM(包括所有本地库),但是一些本地分析其不能分析使用 Java 和 C++实现的应用。

图 6. 本地分析器分析示例图

a7573c9c7c08cdbb41b2e8eba68e4d32.png

图 6 中展示了使用 Oracle Solaris Studio 分析器中分析 GlassFish 启动过程的结果。Oracle Solaris Studio 是一个可以分析 Java 和 C++的本地分析器。从图中可以发现,应用消耗的 CPU 时间为 25.1 秒。其中 JVM-System 消耗 20 秒,包括 JVM 编译器线程,垃圾回收线程以及一些辅助线程。由于在启动过程中需要编译非常多的代码,所以 JVM 编译器线程消耗了绝大多数时间,而垃圾回收线程只消耗了很少的时间。

通过本地分析器我们不仅可以分析优化 JVM 自身功能,更重要的是可以获得应用程序进行垃圾回收的时间。在 Java 分析工具中,垃圾回收线程的信息是无法得到的。

分析过 JVM 本地代码后,我们将对应用程序的启动过程进行分析。如图 7 所示,继在采样模式分析后,方法 defineclass1() 又一次被分析为最耗时的方法。值得关注的是,再次分析结果中,解压读取 jar 文件的方法耗时相对较多。类加载中会用到这些方法,所以证明优化的方向是正确的。由于 Java zip 库中引用的本地代码在其他分析工具中被作为阻塞方法调用,所以在上文各类工具中并没有发现此方法。

图 7. 采样模式分析示例图

ff9b348a26599eefc3eb01610d5849b7.png

无论使用何种性能分析工具,最重要的是熟悉每种工具的优势和劣势。这样才能取长补短,配合使用。开发人员必须学会如何使用性能分析器来找到性能瓶颈,找到需要优化的代码,而不是单纯的关注最耗时的个别方法。

总结

基于采样的性能分析是最常见的一种,因为其相对能做到的分析是有限的,亦或者分析过程所能搜集到的信息是概述性的,往往并不能真实表现应用程序内部的运行情况,但是其分析过程中引入的工作量通常是较低的。不同的采样分析工具行为是不同的,充分利用其优势,做有针对性的分析才是最有意义的。

检测分析能够获得非常多的有关应用程序内部信息,但是前期准备工作往往是非常大的。检测分析方法应当尽量应用在一小节代码中,或者少数几个类、包中。这种方法其实一定程度上限制了对整体应用程序的性能分析,仅适合在程序单元中使用,点对点,针对性较强的分析,采用检测分析的时候,更多时间要求开发人员明确知道哪里有可能产生性能瓶颈。

线程阻塞不一定就是代码编写而产生的,发生线程阻塞时,更多的建议是去想,去看为什么会被阻塞,而不是直接查看代码。尽量采用线程执行时间轴的分析方法。

本地分析提供了既可以深入查看 JVM 内部,同时也可以查看应用程序代码执行的情况。

如果本地分析显示在 GC 过程中大量的使用 CPU 资源,那么调优收集器就是必要的。需要提醒大家的是,编译线程通常是不影响应用程序的性能。

原作者:李 伟军, 宋 翰瀛, 和 杨 翔宇
原文链接:Java 性能分析工具 , 第 2 部分:Java 内置监控工具
原出处:IBM Developer

9c98a31ce99135c93f1794d7ae1fd016.gif

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/454256.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Python面试题(第二篇)

第二部分 网络编程和并发(34题)1、简述 OSI 七层协议。2、什么是C/S和B/S架构?3、简述 三次握手、四次挥手的流程。4、什么是arp协议?5、TCP和UDP的区别?6、什么是局域网和广域网?7、为何基于tcp协议的通信…

noip模拟赛 radius

分析:这道题实在是不好想,一个可以骗分的想法是假定要求的那个点在中心点上,可以骗得不少分.但是在边上的点要怎么确定呢?理论复杂度O(﹢无穷).答案一定是和端点有关的,涉及到最大值最小,考虑二分最大值&…

c语言中int的取值范围_c语言入门(1)

c语言入门C语言一经出现就以其功能丰富、表达能力强、灵活方便、应用面广等特点迅速在全世界普及和推广。C语言不但执行效率高而且可移植性好,可以用来开发应用软件、驱动、操作系统等。C语言也是其它众多高级语言的鼻祖语言,所以说学习C语言是进入编程世…

vue : 无法将“vue”项识别为 cmdlet、函数、脚本文件或可运行程序的名称。请检查名称的拼写,如果包括路径,请确保路径正确, 然后再试一次。

vue : 无法将“vue”项识别为 cmdlet、函数、脚本文件或可运行程序的名称。请检查名称的拼写,如果包括路径,请确保路径正确, 然后再试一次。 报错原因: 没有安装脚手架vue-cli 解决方法:安装脚手架vue-cli npm inst…

session的生命周期

session的生命周期分为创建、活动、销毁三个阶段 创建一个新的会话不代表旧的会话就销毁了 session.invalidate()方法可以销毁当前会话 在page1中写上这个方法再打开网页 说明该会话被销毁了出现了错误 我们把这个方法写在所有代码段的下面 再打开这个网页 刷新网页 这个sessio…

虚拟化与网络

本文转自Grodd51CTO博客,原文链接:http://blog.51cto.com/juispan/1959791,如需转载请自行联系原作者

算法基础之搜索和经典排序

目录 简介 搜索算法 二分法查找 排序算法 冒泡排序(Bubble Sort) 选择排序(Selection Sort) 插入排序(Insert Sort) 快速排序(Quick Sort) 归并排序(Merge Sort…

背景宽高随文本变化_中科大提出ContourNet:更准确的任意形状场景文本检测新方法...

点击上方“CVer”,选择加"星标"置顶重磅干货,第一时间送达本文转载自:CSIG文档图像分析与识别专委会本文简要介绍2020年被CVPR录用的论文“ContourNet: Taking a Further Step toward Accurate Arbitrary-shaped Scene Text Detect…

算法面试题汇总(更新中)

1、根据数字返回相应位置数字 def get_digit(num, i):# i0 个位 1 十位 2 百位...return num // (10 ** i) % 10# print(get_digit(12345, 6)) 2、列表反转,不用内置函数 def reverse_list(li):n len(li)for i in range(n // 2):li[i], li[n-i-1] li[n-i-1], …

使用Jmeter对mysql进行性能测试入门

使用Jmeter对mysql进行性能测试入门 第一步:测试环境准备: 1)、mysql> select version(); ----------- | version() | ----------- | 5.5.13 | ----------- ms数据库数据: mysql> select count(*) from account; ----------…

算法基础之数据结构

whats the 数据结构 数据结构是指相互之间存在着一种或多种关系的数据元素的集合和该集合中数据元素之间的关系组成。 简单来说,数据结构就是设计数据以何种方式组织并存储在计算机中。 比如:列表、集合与字典等都是一种数据结构。 通常情况下&#xff…

soap接口怎么不返回tuple python_Python 中的接口

Python 是动态类型语言, 只在运行时做 Duck Typing 检查.利: 灵活, 方便弊: 代码混乱, 缺少规范标准自带两类接口支持: abc 和 typing.Protocol, 有他们协助给天马行空的程序员套上枷锁, Python 的大工程才可以"上道"abcabc 就是 Abstract Base Class, 虚基类. 跟 Ja…

java 第11次作业:你能看懂就说明你理解了——this关键字

this 代表当前对象 转载于:https://www.cnblogs.com/qingyundian/p/7736699.html

c#多线程操作界面控件的简单实现

一个小功能,早有人实现了。自己在一个项目中用到,觉得有必要记录一下,写下来。代码 从上面你可能已经看出如何多线程操作同一个控件的,就是通过一个委托,然后定义委托方法,判断控件的InvokeRequired属性&am…

ssh 免密_Linux下配置SSH免密通信 “sshkeygen”的基本用法

利用 SSH 协议可以有效防止远程管理过程中的信息泄露问题。SSH最初是UNIX系统上的一个程序,后来又迅速扩展到其他操作平台。1 什么是SSH引用百度百科的说明:SSH 为 Secure Shell的缩写,由 IETF 的网络小组(Network Working Group)所制定;它是…

Python 第三方模块之 NumPy - 科学计算

NumPy 简介 NumPy 发展历史 1995年 Jim HugUNin开发了Numeric。随后,Numarray包诞生。Travis Oliphants整合Numeric和Numarray,开发Numpy,于2006年发布第一个版本。Numpy(Numeric Python)提供了许多高级的数值编程工…

Python 第三方模块之 matplotlib - 绘图库

简介 matplotlib是受MATLAB的启发构建的。MATLAB是数据绘图领域广泛使用的语言和工具。MATLAB语言是面向过程的。利用函数的调用,MATLAB中可以轻松的利用一行命令来绘制直线,然后再用一系列的函数调整结果。 matplotlib有一套完全仿照MATLAB的函数形式…

微软P2V工具之Disk2VHD

虚拟化经过最近几年的发展,已经有很多的应用和服务迁移到了虚拟化的平台上了。在实施虚拟化的过程中就会涉及到将原来老旧的服务器来迁移到虚拟化平台的运行,这就是P2V,物理机转换为虚拟机。谈到P2V大家会想到很多的工具,例如Vmwa…

生成n套数位加减乘除_leetcode 算法汇总(四)位运算

一、 运算符& 与运算: 两个位都是 1 时,结果才为 1,否则为 0| 或运算: 两个位都是 0 时,结果才为 0,否则为 1^ 异或运算: 两个位相同则为 0,不同则为 1~ 取反运算:0 …

机器学习算法之 K-means、层次聚类,谱聚类

k-means 和层次聚类都属于划分聚类,实际中最常用的是k-means,k-means效果不好的情况下才会采用其他聚类 K-means算法 K-means算法,也称为K-平均或者K-均值,是一种使用广泛的最基础的聚类算法 假设输入样本为TX1,X2,…,Xm;则算法…