BEA JRockit Java虚拟机(JVM)所带来的不仅仅是性能的提升本文探讨了JRockit R版本可用的一些管理和使用方面的特性概述了JRockit Mission Control分析工具套件JRockit Management Console的试验性headless模式以及使用CtrlBreak HandlerJRCMD堆视图和code coverage与JVM进行交互 简介 JRockit JVM不只是快它还和JRockit Mission Control一起组成一套执行运行时分析和内存洩漏检测的分析工具JRockit Management Console包含在JRockit JDK中本文将探讨JRockit Management Console的一种试验性的headless模式它可以用于与来自命令行的基于JRockitJMX的管理代理进行交互CtrlBreak Handler提供了一种向JRockit发送各种高级命令的方法甚至是在它启动后这些命令甚至可以远程调用我在后文中会提及最后我探讨了试验性的code coverageJRockit开箱即用地提供了该特性 关于BEA JRockit的更多信息参见devdev网站的JRockit Product Center 首先我将快速概述一下JRockit JVM可用的已确定的管理工具然后我会转向缺少文档的试验性管理特性 JRockit Mission Control JRockit R版本引入了JRockit Mission Control工具套件它包含的工具可以进行监控管理分析和消除Java应用程序内存洩漏而不会引起通常与此类工具相关联的性能开销Mission Control的低性能开销是因为使用了作为JRockit常规适应性动态调优的一部分而收集的数据这还可以消除工具使用字节码装置修改系统执行特性时发生Heisenberg异常的问题JRockit Mission Control功能可以根据需要随时可用低性能开销也只在运行工具时有效这些特征使得JRockit Mission Control成为专门用于生产中系统的工具 JRockit Mission Control中包含以下工具 JRockit Management Console JRockit Management Console用于监控和管理多个JRockit实例它捕获并显示关于垃圾收集器(GC)暂停内存和CPU使用的实时数据以及部署在JVM内部MBean服务器上的所有JMX MBean的信息JVM管理包括对CPU相似性垃圾收集策略和内存池大小的动态控制 JRockit Runtime Analyzer JRockit Runtime Analyzer(JRA)是一个随需应变的动态记录器它生成关于JVM和正在运行的应用程序的详细记录然后可以使用JRA应用程序对记录下来的配置文件进行离线分析所记录的数据包括对方法和锁定的分析还有垃圾收集统计信息优化决策以及对象统计信息 JRockit Memory Leak Detector JRockit Memory Leak Detector工具用来发现和查找内存洩漏原因Memory Leak Detector的趋势分析器可以发现非常缓慢的洩漏显示详细的堆统计信息(包括指向洩漏对象和分配位置的引用类型和实例)并快速找出洩漏原因Memory Leak Detector使用先进的图形化表现技术以便更容易定位和理解有时比较复杂的信息 关于JRockit Mission Control的更多信息可以阅读文章An Introduction to JRockit Mission Control或者访问devdev网站的JRockit Mission Control JRockit Management Console的Headless模式(试验性) JRockit Management Console是监控JRockit运行的工具它包括两部分一个运行在JVM进程中的JMX代理一个使用图形化用户界面的独立客户端(关于它以及其它方面的更详细的信息请参见An Introduction to JRockit Mission Control)其中用户界面可以绘出部署在所连接的Java虚拟机中的任何MBean的数值属性的图形图形密集的应用程序对资源的消耗可能会相当厉害JRockit Management Console也不例外可以引入textonly(纯文本)模式以便使用Management Console的通知功能和数据收集工具而不会导致整个GUI的开销 headless控制台引入了大量新的命令行参数这同样适用于控制台的GUI版本参数包括 | 参数 | 描述 | headless以headless模式启动控制台(不会加载与GUI相关的类)settings <settings file>使用指定配置文舳H绻讷UI模式启动并且该文件不存在那么它将在关闭Management Console时创建connectall连接配置文件中所有可用连接(即原先使用GUI添加的)connect <connection > <connection > <> 使用GUI连接配置文件中可用的指定连接autoconnect自动连接到运行在启用JRockit发现协议(JRockit Discovery ProtocolJDP)的管理服务器上的任何JRockituptime <time in seconds>将控制台运行一段指定的时间然后自动关闭它useraction <name> <delay in seconds> <period (optional)>经过指定的时延后运行指定的用户动作如果不指定period动作将只执行一次如果指定动作将每过<period>秒就执行一次version打印Management Console的版本信息并退出locale <language> <country (optional)>使用特定的地区启动控制台比如locale ja JP将以日语启动控制台(JRockit R可用)这里给出一个以headless模式启动Management Console的例子读取指定配置文件尝试连接所有已指定的JRockit使用JRockit发现协议(JDP下文讨论)积极查找新的JRockit秒后将以每分钟一次的间隔向所有连接的JRockit发送CtrlBreak命令一小时之后自动关闭以前加入指定连接的所有通知规则(不管是通过使用GUI还是通过直接编辑配置文件添加的)将生效
java jar ManagementConsolejar headless settings C:\Headless\consolesettingsxml connectall autoconnect uptime useraction ctrlbreak
用户动作是可以与JRockit Management Console上的一组连接进行交互的插件类同样使用控制台配置文件来存储配置数据用户动作显示在JRockit控制台图形用户界面的Plugins菜单下headless模式中也可用随控制台提供了两个默认用户动作jrarecording用户动作对连接的JRockit启动JRA记录ctrlbreak用户动作向连接的JRockit发送CtrlBreak命令(参见本文中关于CtrlBreak Handler和JRockit运行时分析器的小节)要指定特定用户动作的参数可以使用GUI进行配置也可以编辑Management Console配置文件后者可以在<userhome>/ManagementConsole/ManagementConsole/consolesettings<version>xml文件中找到
编写自己的用户动作很容易首先创建一个AbstractUserAction的子类该示例演示了如何创建一个从所有连接的JRockit获取线程堆栈转储的用户动作
package comexampleuseractions;import javaioIOException;import javautilList;import nsolerjmxCommonRJMXNames;import nsolerjmxRJMXConnectorModel;import nsoleuseractionsAbstractUserAction;/** * This is a simple user action getting stackdumps from * the selected JRockits and printing them on stdout * * @author Marcus Hirt */public class MyUserAction extends AbstractUserAction{ public void executeAction(List connections) { for (RJMXConnectorModel connection : connections) { if (connectionisConnected()) { try { Systemoutprintln(CommonRJMXNamesgetThreadMXBean(connection)getThreadStackDump()); } catch (IOException e) { eprintStackTrace(); } } } }}
接下来需要在consolesettingsxml文件中配置部属描述符以便用户动作对于控制台可用可以在配置文件中发现user_actions元素它已经填充了一些user_action元素示例动作的部署描述符应当以相同的样式输入描述符看起来会是这样
<user_action> <user_action_class>comexampleuseractionsMyUserAction</user_action_class> <user_action_name>stackdump</user_action_name> <user_action_menu_name>Stack Dump on stdout</user_action_menu_name> <user_action_description>Gets a stack dump from the selected JRockit(s) and dumps it on stdout</user_action_description></user_action>
这也使得用户动作在Plugins菜单下的用户界面中可见
当控制台启动或退出时如果有设置/状态需要从配置文件加载/保存只需重写exportToXml()/importFromXml()方法如示例中所示
/** * @see nsoleutilXmlEnabled * #exportToXml(orgwcdomElement) */public void exportToXml(Element parentNode){ superexportToXml(parentNode); XmlToolkitsetSetting(parentNode MY_PROPERTY m_myVal);}/** * @see nsoleutilXmlEnabled * #initializeFromXml(orgwcdomElement) */ public void initializeFromXml(Element parentNode) { superinitializeFromXml(parentNode); m_myVal = XmlToolkitgetSetting(parentNode MY_PROPERTY DEFAULT_MY_VALUE));}
注意用户动作的名称是使用launcher启动参数时将引用的用户动作名称菜单名是会在GUI菜单中显示的名称更多的信息请参见user action docs和JLMEXT docs注意这只是一个试验性的功能提供的文档还相当简单编写定制的通知动作和约束的方式与此类似更多信息请参见Management Console User Guide
JRockit发现协议(JDP)
JDP(JRockit发现协议)是个简单且有效的协议用于允许JRockit管理服务器向Management Console组播它的存在下面的两个表分别列出了在服务器端和客户端控制JDP行为的系统属性
管理服务器的JDP属性
系统属性 | 描述 | 默认值 | jrockitmanagementserverautodiscovery 启用JRockit发现协议Falsejrockitmanagementserverdiscoveryperiod在两个ping之间需要等待多久(以毫秒为单位)jrockitmanagementl活跃的跃点数jrockitmanagementserverdiscoveryaddress所使用的组播地址jrockitmanagementserverdiscoveryport所使用的组播端口Management Console的JDP属性
系统属性 | 描述 | 默认值 | nsolepreferencesjdpport用于JRockit发现协议的端口nsolepreferencesjdpaddress所使用的组播地址这里给出了在服务器端启用JDP的情况下启动JRockit需要最少参数的示例
java Xmanagement Djrockitmanagementserverautodiscovery=true<your program>
CtrlBreak Handler
您是否曾经希望在JVM启动后可以使用一种轻松的方式与其交互?假如说您忘记添加Xmanagement选项来启动管理服务器或者您想改变运行系统中GC的冗余级别这些现在很容易通过重新配置CtrlBreak Handler来完成而且它不只是打印堆栈跟蹤
用法
创建一个名为ctrlhandleract的文件
向ctrlhandleract文件添加命令(参见下文命令列表)
以stop结束文件这是结束文件分析的保留命令
按下ctrlbreak每一个命令都将以出现的顺序执行
JRockit首先会在当前工作目录查找该文件如果未找到JRockit将在JVM目录中查找如果仍然没有的话JRockit将回退以生成一个常规的线程堆栈转储JRockit将在每次按下ctrlbreak时读取act文件因此用户可以在方便时重新配置该文件而同时JRockit仍在运行
这里给出一个示例act文件它首先打印时间戳然后是用于启动JRockit的命令行最后是一个线程堆栈转储它还包括可以用于act文件的有用命令的列表
# Example ctrlhandleract filetimestampcommand_lineprint_threadsstop# set_filename filename=<file> [append=true]# Sets the file that all handlers following this command will# use for printing You can have several set_filename commands# in a file It takes two arguments: filename and an optional# append to specify if you want to append to the file # or overwrite it Default is to overwrite the file # timestamp# Prints a timestamp # print_threads# The normal thread dump# verbosity [args=<components>] [filename=<file>]# Changes the verbosity level normally specified with Xverbose # version# Prints JRockit version information # command_line# Prints the command line used to start JRockit # print_object_summary# Prints heap usage statistics (how much heap is used per class)# together with a delta on how much this has changed since# the last invocation of this ctrlbreak handler# print_memusage# Prints a memory usage report of how JRockit is using# the memory# heap_diagnostics# Prints a detailed report of the heap including ascii graphics # over the heap layout# print_class_summary# Prints all loaded classes # print_utfpool# Print all UTF strings # jrarecording [filename=<file>] [time=<time>] [nativesamples=true]# Starts a JRA recording# run_optfile [filename=<file>]# See OptFile # start_management_server# Starts the new JMXbased management agent # kill_management_server# Stops the management agent # start_rmp_server# Starts the old management server (actually the listening # socket that in turn starts servers whenever a connection# is established) # kill_rmp_server# Stops the old management server (actually shuts down the# listening socket) The only reason it isnt named # kill_rmp_server is that stop is a reserved keyword # that stops the parsing of the act file ;) # help [ctrlbreak handler]# Prints all available ctrlbreak handlers if no argument # is specified or help for the specified ctrlbreak handler# memleakserver [port=<port>]# Toggles the memleakserver If it hasnt been started # it will be started If it has already started it will be# shut down The default port is # verbose_referents action=[heap|full|nursery|start|stop]# Print verbose reference information# Parameters:# action=[heap|full|nursery|start|stop]# heap trigger a heap collection and output reference# information# full trigger a full heap collection (clears softly # reached soft referents)# nursery trigger a nursery collection (heap collection # if running without nursery)# start start writing reference information to default# verbose stream# stop stop writing reference information# print_exceptions # exceptions=[true|all|false] stacktraces=[true|all|false]# Enable printing of Java exceptions thrown in the VM# Parameters:# exceptions print exceptions# stacktraces print exceptions with stacktraces# At least one of the parameters is required# Values for the parameters can be true|all|false# true print all exceptions # except java/util/EmptyStackException# java/lang/ClassNotFoundException and # java/security/PrivilegedActionException# all print all exceptions# false dont print exceptions# To turn exception printing off completely you need to set# exceptions = false even if it was turned # on by stacktraces = trueJRCMD使用JRCMD实用工具是一种新的调用CtrlBreak Handler的便捷方式可在JRockit发行版的bin目录中找到它用法jrcmd <PID> <command> <parameters>
JRCMD
使用JRCMD实用工具是一种新的调用CtrlBreak Handler的便捷方式可在JRockit发行版的bin目录中找到它
用法 jrcmd <PID> <command> <parameters>
PID = 要在其中执行CtrlBreak Handler的JRockit进程的进程ID
command = 要执行的CtrlBreak Handler命令
parameters = CtrlBreak Handler的参数
如果不指定选项(或者只指定P)那么将显示运行在本地机器上的所有JRockit的进程ID如果PID设为那么命令将发送给在本地机器上运行的所有JRockit JVM
要列出特定的JRockit中有哪些CtrlBreak Handler可用可以使用help命令
jrcmd <PID> help
要想获得某个具体的CtrlBreak Handler的帮助信息需要在help后添加CtrlBreak Handler的名称比如
jrcmd help kill_management_server
也可以使用JRCMD列出指定进程的性能计数
jrcmd <PID> l
远程调用CtrlBreak Handler
可以使用JRockit Management Console来远程调用CtrlBreak Handler存在一个对JRockitConsoleMBean的操作称为runCtrlBreakHandlerWithResultJRockit Management Console可以从属性浏览器调用对MBean的操作这里有关于如何调用CtrlBreak Handler的逐步描述
连接到一个运行中的JRockit
右击该连接选择Browse Attributes
展开comjrockit domain文件夹选择JRockitConsole MBean
单击operations选项卡查看可用操作
单击String parameter参数按钮找到runCtrlBreakHandlerWithResult操作
输入希望执行的CtrlBreak Handler名称语法与ctrlhandleract文件相同按下OK
按下Execute按钮执行操作
试着输入help作为参数将会列出所有可用的CtrlBreak Handler如图所示
图从JRockit Management Console调用CtrlBreak Handler(单击图片查看大图)
堆视图(试验性)
当分析应用程序如何使用某种垃圾收集策略时在每一次GC后对堆进行快照将会非常有帮助这有助于开发人员研究数据比如碎片/压缩以及算法通常如何执行但是快照中包含如此多的数据量以至于查看它没有什么意义因此JRockit团队开发了一个提供图形化表示的小工具以便更好地进行说明
图显示了一个快照的例子(使用的是一个非常早的JRockit 预发布版本)
每一排表示一次垃圾收集左边是开始的堆右边是结束的堆堆显示的右边是一个可配置图形实心白色区域表示空白堆黑色区域是充实区(也就是填充了对象的区域)浅灰色区域是碎片区红色黄色和绿色区域是可配置图形可以从命令行指定在可配置图形中显示什么该工具依然很粗糙对于用户也不够友好不过毋庸置疑它对JRockit的终端用户非常有用所以这是一个非常不错但是不能通用的工具
code coverage(试验性)
很多开发人员在以某种方式使用他们的应用程序时使用code coverage分析来研究诸如代码库中的多少以及哪些部分正在运行之类的状况测试人员喜欢使用code coverage来度量测试套件覆盖应用程序的比例但是对于大型应用程序由code coverage工具所引起的性能开销通常是被禁止的
JRockit内置了高性能的行code coverage当启用code coverage运行时代码将由记录行命中的捕获器生成一旦某行被命中并记录就删除捕获器JRockit可以继续以接近全速的速度运行
要使JRockit记录code coverage数据必须指定一个命令行选项
用法 Xcodecoverage
可以使用以下系统属性来控制该行为
系统属性 | 描述 | decoveragefilter=<filterspec>filterspec是个以分号(Windows)或冒号(Linux)隔开的筛选器字符串列表它定义哪些类应当被覆盖以开头的筛选器字符串会被视为不应当覆盖的类
示例
decoveragefilter=
java/util/Hashtable;com/bea/*;com/bea/bla*
decoveragefilterfile=<filename>设置包含筛选器定义的文件的文件名文件格式为每行一个筛选器字符串decoverageoutputfile=
<filename>设置存放输出的文件如果写入<filename>_输出文件不能被打开那么将尝试<filename>_以此类推在多个JVM共享一个公共命令行的情况中这可能会很有用decoveragetestid=
<idstring>设置初始测试标识符decoverageverbose使code coverage更为详细适用于在覆盖文件(均是纯文本文件)中执行文本比较decoverageappendoutput设置对输出文件的写入为追加而不是覆盖
这里给出特定于code coverage的参数用于生成如下图中所示的数据
Xcodecoverage decoveragefilter=com/jrockit/console/*;com/jrockit/common/* decoverageoutputfile=console_coveragetxt
在内部由一个code coverage小工具来解释JRockit所生成的数据如图所示
图code coverage工具的输出示例
结束语
BEA对Java运行时的掌控将其置于一个独一无二的位置BEA交付了一些针对Java平台的低开销的管理和监控特性很多针对BEA JRockit的有趣的管理和使用特性正在开发中其中一些已经随着包含在JRockit R中的JRockit Mission Control而可以使用更多特性也即将出现更多信息请参见Mission Control home page