JROCKIT 5.0——輕鬆玩轉JVM

  bea jrockit java虛擬機(jvm)所帶來的不僅僅是性能的提升。本文探討了jrockit 5.0 r26版本可用的一些管理和使用方面的特性。概述了jrockit mission control分析工具套件、jrockit management console的試驗性headless模式以及使用ctrl-break handler、jrcmd、堆視圖和code coverage與jvm進行互動。

簡介
jrockit jvm不只是快,它還和jrockit mission control一起,組成一套執行運行時分析和記憶體泄漏檢測的分析工具,jrockit management console包含在jrockit jdk中。本文將探討jrockit management console的一種試驗性的headless模式,它可以用於與來自命令行的基於jrockitjmx的管理代理進行互動。ctrl-break handler提供了一種向jrockit傳送各種高級命令的方法,甚至是在它啟動後。這些命令甚至可以遠程調用,我在後文中會提及。最後,我探討了試驗性的code coverage,jrockit開箱即用地提供了該特性。

關於bea jrockit的更多信息,參見dev2dev網站的jrockit product center。

首先我將快速概述一下jrockit jvm可用的已確定的管理工具,然後我會轉向缺少文檔的試驗性管理特性。

jrockit mission control
jrockit r26.0.0版本引入了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,或者訪問dev2dev網站的jrockit mission control。

jrockit management console的headless模式(試驗性)

jrockit management console是監控jrockit運行的工具。它包括兩部分:一個運行在jvm進程中的jmx代理,一個使用圖形化用戶界面的獨立客戶端(關於它以及其它方面的更詳細的信息,請參見an introduction to jrockit mission control)。其中,用戶界面可以繪出部署在所連線的java虛擬機中的任何mbean的數值屬性的圖形。圖形密集的應用程式對資源的消耗可能會相當厲害,jrockit management console也不例外。可以引入text-only(純文本)模式,以便使用management console的通知功能和數據收集工具而不會導致整個gui的開銷。

headless控制台引入了大量新的命令行參數。這同樣適用於控制台的gui版本。參數包括:

參數描述-headless以headless模式啟動控制台(不會載入與gui相關的類)。-settings <settings file>使用指定配置檔案啟動。如果以gui模式啟動,並且該檔案不存在,那么它將在關閉management console時創建。-connectall連線配置檔案中所有可用連線(即原先使用gui添加的)。-connect <connection 1> <connection 2> <...> 使用gui連線配置檔案中可用的指定連線。-autoconnect自動連線到運行在啟用jrockit發現協定(jrockit discovery protocol,jdp)的管理伺服器上的任何jrockit。-uptime <time in seconds>將控制台運行一段指定的時間,然後自動關閉它。-useraction <name> <delay in seconds> <period (optional)>經過指定的時延後運行指定的用戶動作。如果不指定period,動作將只執行一次;如果指定,動作將每過<period>秒就執行一次。-version列印management console的版本信息,並退出。-locale <language> <country (optional)>使用特定的地區啟動控制台,比如,-locale ja jp將以日語啟動控制台(jrockit r27可用)。

這裡給出一個以headless模式啟動management console的例子,讀取指定配置檔案,嘗試連線所有已指定的jrockit,使用jrockit發現協定(jdp,下文討論)積極查找新的jrockit。30秒後將以每分鐘一次的間隔向所有連線的jrockit傳送ctrl-break命令。一小時之後自動關閉。以前加入指定連線的所有通知規則(不管是通過使用gui還是通過直接編輯配置檔案添加的)將生效。

java -jar managementconsole.jar -headless -settings c:\headless\consolesettings.xml -connectall -autoconnect -uptime 3600 -useraction ctrlbreak 30 60

用戶動作是可以與jrockit management console上的一組連線進行互動的外掛程式類,同樣使用控制台配置檔案來存儲配置數據。用戶動作顯示在jrockit控制台圖形用戶界面的plugins選單下,headless模式中也可用。隨控制台提供了兩個默認用戶動作:jrarecording用戶動作,對連線的jrockit啟動jra記錄;ctrlbreak用戶動作,向連線的jrockit傳送ctrl-break命令(參見本文中關於ctrl-break handler和jrockit運行時分析器的小節)。要指定特定用戶動作的參數,可以使用gui進行配置,也可以編輯management console配置檔案,後者可以在<user.home>/managementconsole/managementconsole/consolesettings.<version>.xml檔案中找到。

編寫自己的用戶動作很容易。首先創建一個abstractuseraction的子類。該示例演示了如何創建一個從所有連線的jrockit獲取執行緒堆疊轉儲的用戶動作。

package com.example.useractions;import java.io.ioexception;import java.util.list;import com.jrockit.console.rjmx.commonrjmxnames;import com.jrockit.console.rjmx.rjmxconnectormodel;import com.jrockit.console.useractions.abstractuseraction;/** * 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 (connection.isconnected()) { try { system.out.println(commonrjmxnames.getthreadmxbean(connection).getthreadstackdump()); } catch (ioexception e) { e.printstacktrace(); } } } }}

接下來,需要在consolesettings.xml檔案中配置部屬描述符,以便用戶動作對於控制台可用。可以在配置檔案中發現user_actions元素,它已經填充了一些user_action元素。示例動作的部署描述符應當以相同的樣式輸入。描述符看起來會是這樣:

<user_action> <user_action_class>com.example.useractions.myuseraction</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 com.jrockit.console.util.xmlenabled * #exporttoxml(org.w3c.dom.element) */public void exporttoxml(element parentnode){ super.exporttoxml(parentnode); xmltoolkit.setsetting(parentnode, my_property, m_myval);}/** * @see com.jrockit.console.util.xmlenabled * #initializefromxml(org.w3c.dom.element) */ public void initializefromxml(element parentnode) { super.initializefromxml(parentnode); m_myval = xmltoolkit.getsetting(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屬性 系統屬性描述默認值jrockit.managementserver.autodiscovery 啟用jrockit發現協定falsejrockit.managementserver.discovery.period在兩個ping之間需要等待多久(以毫秒為單位)5000jrockit.managementserver.discovery.ttl活躍的躍點數1jrockit.managementserver.discovery.address所使用的組播地址232.192.1.212jrockit.managementserver.discovery.port所使用的組播連線埠7095

management console的jdp屬性 系統屬性描述默認值com.jrockit.console.preferences.jdp.port用於jrockit發現協定的連線埠7095com.jrockit.console.preferences.jdp.address所使用的組播地址232.192.1.212

這裡給出了在伺服器端啟用jdp的情況下,啟動jrockit需要最少參數的示例。

java -xmanagement -djrockit.managementserver.autodiscovery=true<your program>

ctrl-break handler

您是否曾經希望在jvm啟動後可以使用一種輕鬆的方式與其互動?假如說您忘記添加-xmanagement選項來啟動管理伺服器,或者您想改變運行系統中gc的冗餘級別。這些現在很容易通過重新配置ctrl-break handler來完成,而且它不只是列印堆疊跟蹤。

用法 創建一個名為ctrlhandler.act的檔案。 向ctrlhandler.act檔案添加命令(參見下文命令列表)。 以“stop”結束檔案,這是結束檔案分析的保留命令。 按下ctrl-break,每一個命令都將以出現的順序執行。

jrockit首先會在當前工作目錄查找該檔案。如果未找到,jrockit將在jvm目錄中查找。如果仍然沒有的話,jrockit將回退以生成一個常規的執行緒堆疊轉儲。jrockit將在每次按下ctrl-break時讀取act檔案,因此用戶可以在方便時重新配置該檔案,而同時jrockit仍在運行。

這裡給出一個示例act檔案,它首先列印時間戳,然後是用於啟動jrockit的命令行,最後是一個執行緒堆疊轉儲。它還包括可以用於act檔案的有用命令的列表:

# example ctrlhandler.act 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 ctrl-break 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_utf8pool# print all utf8 strings. # jrarecording [filename=<file>] [time=<time>] [nativesamples=true]# starts a jra recording.# run_optfile [filename=<file>]# see optfile. # start_management_server# starts the new jmx-based 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 isn't named # kill_rmp_server is that stop is a reserved keyword # that stops the parsing of the act file. ;) # help [ctrl-break handler]# prints all available ctrl-break handlers if no argument # is specified, or help for the specified ctrl-break handler.# memleakserver [port=<port>]# toggles the memleakserver. if it hasn't been started # it will be started. if it has already started, it will be# shut down. the default port is 7095.# 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 - don't print exceptions# to turn exception printing off completely you need to set# exceptions = false even if it was turned # on by stacktraces = true.jrcmd使用jrcmd實用工具是一種新的調用ctrl-break handler的便捷方式,可在jrockit發行版的bin目錄中找到它。用法jrcmd <pid> <command> <parameters>

jrcmd
使用jrcmd實用工具是一種新的調用ctrl-break handler的便捷方式,可在jrockit發行版的bin目錄中找到它。

用法 jrcmd <pid> <command> <parameters> pid = 要在其中執行ctrl-break handler的jrockit進程的進程id。 command = 要執行的ctrl-break handler命令。 parameters = ctrl-break handler的參數。

如果不指定選項(或者只指定-p),那么將顯示運行在本地機器上的所有jrockit的進程id。如果pid設為0,那么命令將傳送給在本地機器上運行的所有jrockit jvm。

要列出特定的jrockit中有哪些ctrl-break handler可用,可以使用help命令:

jrcmd <pid> help

要想獲得某個具體的ctrl-break handler的幫助信息,需要在help後添加ctrl-break handler的名稱,比如:

jrcmd 0 help kill_management_server

也可以使用jrcmd列出指定進程的性能計數:

jrcmd <pid> -l

遠程調用ctrl-break handler
可以使用jrockit management console來遠程調用ctrl-break handler。存在一個對jrockitconsolembean的操作,稱為runctrlbreakhandlerwithresult。jrockit management console可以從屬性瀏覽器調用對mbean的操作。這裡有關於如何調用ctrl-break handler的逐步描述。

連線到一個運行中的jrockit。 右擊該連線,選擇browse attributes。 展開com.jrockit domain資料夾,選擇jrockitconsole mbean。 單擊operations選項卡,查看可用操作。 單擊string parameter參數按鈕,找到runctrlbreakhandlerwithresult操作。 輸入希望執行的ctrl-break handler名稱。語法與ctrlhandler.act檔案相同。按下ok。 按下execute按鈕,執行操作。

試著輸入“help”作為參數,將會列出所有可用的ctrl-break handler,如圖1所示。


圖1.從jrockit management console調用ctrl-break handler(單擊圖片查看大圖)

堆視圖(試驗性)
當分析應用程式如何使用某種垃圾收集策略時,在每一次gc後對堆進行快照將會非常有幫助。這有助於開發人員研究數據,比如碎片/壓縮以及算法通常如何執行。但是快照中包含如此多的數據量以至於查看它沒有什麼意義,因此jrockit團隊開發了一個提供圖形化表示的小工具,以便更好地進行說明。

圖2顯示了一個快照的例子(使用的是一個非常早的jrockit 1.4.2預發布版本):

每一排表示一次垃圾收集。左邊是開始的堆,右邊是結束的堆。堆顯示的右邊是一個可配置圖形。實心白色區域表示空白堆,黑色區域是充實區(也就是填充了對象的區域),淺灰色區域是碎片區,紅色、黃色和綠色區域是可配置圖形。可以從命令行指定在可配置圖形中顯示什麼。該工具依然很粗糙,對於用戶也不夠友好,不過毋庸置疑它對jrockit的終端用戶非常有用,所以這是一個非常不錯但是不能通用的工具。

code coverage(試驗性)
很多開發人員在以某種方式使用他們的應用程式時,使用code coverage分析來研究諸如代碼庫中的多少以及哪些部分正在運行之類的狀況。測試人員喜歡使用code coverage來度量測試套件覆蓋應用程式的比例。但是,對於大型應用程式,由code coverage工具所引起的性能開銷通常是被禁止的。

jrockit內置了高性能的行code coverage。當啟用code coverage運行時,代碼將由記錄行命中的捕獲器生成。一旦某行被命中並記錄,就刪除捕獲器,jrockit可以繼續以接近全速的速度運行。

要使jrockit記錄code coverage數據,必須指定一個命令行選項。

用法 -xcodecoverage

可以使用以下系統屬性來控制該行為:

系統屬性描述jrockit.codecoverage.filter=
<filterspec>filterspec是個以分號(windows)或冒號(linux)隔開的篩選器字元串列表,它定義哪些類應當被覆蓋。以“-”開頭的篩選器字元串會被視為不應當覆蓋的類。

示例:
-djrockit.codecoverage.filter=
java/util/hashtable;com/bea/*;-com/bea/bla.*

jrockit.codecoverage.filterfile=
<filename>設定包含篩選器定義的檔案的檔案名稱。檔案格式為每行一個篩選器字元串。jrockit.codecoverage.outputfile=
<filename>設定存放輸出的檔案。如果寫入<filename>_0,輸出檔案不能被打開,那么將嘗試<filename>_1,以此類推。在多個jvm共享一個公共命令行的情況中,這可能會很有用。jrockit.codecoverage.testid=
<id-string>設定初始測試標識符。jrockit.codecoverage.verbose使code coverage更為詳細。適用於在覆蓋檔案(均是純文本檔案)中執行文本比較。jrockit.codecoverage.appendoutput設定對輸出檔案的寫入為追加而不是覆蓋。

這裡給出特定於code coverage的參數,用於生成如下圖中所示的數據。

-xcodecoverage -djrockit.codecoverage.filter=com/jrockit/console/*;com/jrockit/common/* -djrockit.codecoverage.outputfile=console_coverage.txt

在內部,由一個code coverage小工具來解釋jrockit所生成的數據,如圖3所示。


圖3:code coverage工具的輸出示例(點擊圖片查看大圖)

結束語
bea對java運行時的掌控將其置於一個獨一無二的位置:bea交付了一些針對java平台的低開銷的管理和監控特性。很多針對bea jrockit的有趣的管理和使用特性正在開發中。其中一些已經隨著包含在jrockit 5.0 r26中的jrockit mission control而可以使用,更多特性也即將出現。更多信息請參見mission control home page。

參考資料

an introduction to jrockit mission control,marcus hirt撰寫(dev2dev,2005年12月) memory leaks, be gone,staffan larsen撰寫(dev2dev,2005年6月)——提供了關於記憶體泄漏檢測系統的大量信息 new features and tools in jrockit 5.0,eva andreasson撰寫(dev2dev,2005年2月) ——提供了一份很早但卻很有用的、jrockit 5.0中的多個特性的匯總 dev2dev jrockit product center——包含大量可以訂閱的信息和部落格 mission control section,dev2dev——包含jrockit工具的更多信息