java平臺標準版(java se)6,代碼名爲"mustang",是最新的java se發行版本(正在開發中)。java se 6源碼和二進制代碼均可以在www.java.net上下載。java se 6平臺要到2006年秋天才能正式發佈。不過,如今你能夠下載試用java se 6 beta版。
java se 6平臺中提供了多種可觀察性(observability)工具,這其中的許多工具均可在系統中運行,而這些工具中的只有極少數被用於掛起進程或核心複製處理。所以,在本文中,咱們將分析這些可觀察性工具在進程上的效果。
1、 在java se 6平臺中的可觀察性工具-dtrace
在java se 6軟件中又引入了許多可觀察性改進功能。儘管其中大多數可適用於全部的平臺,可是其中的一些改進僅是特定於solaris
操做系統(特別針對solaris 10及更高版本)的。在j2se 5.0平臺中,引入了一種新的動態跟蹤(dtrace)行爲――jstack。正如咱們已經瞭解的,jstack可以打印混合模式堆棧跟蹤信息(java和本機c/c++語言是以幀方式顯示的)。當從一個給定的java進程中發出pollsys系統調用時,下列d腳本將輸出對混合模式堆棧的跟蹤信息:
#!/usr/sbin/dtrace -s syscall::pollsys:entry / pid == $1 / { /*打印至多50幀*/ jstack(50); } |
下面是上面腳本的運行結果:
libc.so.1`__pollsys+0xa libc.so.1`poll+0x52 libjvm.so`int os_sleep(long long,int)+0xb4 libjvm.so`int os::sleep(thread*,long long,int)+0x1ce libjvm.so`jvm_sleep+0x1bc java/lang/thread.sleep dtest.method3 dtest.method2 dtest.method1 dtest.main [...篇幅所限,刪去了一些輸出結果...] |
其實,jstack就是java可觀察性在solaris 10 os及以上版本中的一個頗有用的起點。可是,java se 6中遠不止這些,它新增長了許多針對java虛擬機(jvm)可觀察性和java應用程序可觀察性的dtrace probe。java se 6發行中增長兩種jvm特定的dtrace提供者-hotspot和hotspot_jni。
2、 hotspot提供者
hotspot提供者增長了許多探針,它們能夠大體地做以下分類:
? vm生命週期探針-vm啓動,關閉事件
? 線程生命週期探針-線程啓動,中止,等等
? 類加載探針-一個java類加載或卸載
? 垃圾收集探針-gc啓動,結束
? 方法編譯探針-java字節碼-到-本機代碼編譯("hotspot編譯")
? 監視器探針-java監視競爭性入口,通知,通知所有,等等
? 應用程序探針-java對象分配,java方法入口/返回,等等
有關於這些探針的更爲詳細的信息,請參考keith mcguigan的博客。下面是使用這些探針的一些示例。
(一) 打印java線程的名稱
hotspot$1:::thread-start { self->ptr = (char*) copyin(arg0, arg1+1); self->ptr[arg1] = '/0'; self->threadname = (string) self->ptr; printf("thread %s started/n", self->threadname); } |
(二) 在d腳本中的-verbose:class等價物
你可能已經使用過-verbose:class jvm選項。當一個java類加載或卸載時,這個選項可以使jvm打印一個跟蹤消息。下面是使用dtrace獲得相同結果的狀況:
/*當每一個類加載時,打印出其各自的名稱*/ hotspot$1:::class-loaded { self->str_ptr = (char*) copyin(arg0, arg1+1); self->str_ptr[arg1] = '/0'; self->name = (string) self->str_ptr; printf("class %s loaded/n", self->name); } |
(三) 打印異常中的棧跟蹤信息(除了混合模式)
throwable.printstacktrace()方法打印一個包含java幀的堆棧跟蹤。這個d腳本將打印java代碼,java本機接口(jni)代碼,c/c++代碼以及os c/c++代碼的全部的幀-不管什麼時候引起一個例外。
hotspot$1:::method-entry { self->ptr = (char*)copyin(arg1, arg2+1); self->ptr[arg2] = '/0'; self->classname = (string)self->ptr; self->ptr = (char*)copyin(arg3, arg4+1); self->ptr[arg4] = '/0'; self->methodname = (string)self->ptr; } hotspot$1:::method-entry / self->classname == "java/lang/throwable" && self->methodname == "<init>" / { jstack(); } |
在java代碼中的全部的異常和錯誤都直接或間接地派生自java.lang.throwable,所以全部的異常構造器最後都將調用java.lang.throwable的構造器。這個d腳本創建一個方法入口探針-使用一個針對該構造器的過濾器(注意,<init>是構造器方法的內部名)。當調用這個構造器時,jstack()行爲將打印混合模式堆棧跟蹤。
(四) java堆直方圖
咱們可使用object-alloc探針來構建一個java堆直方圖,以下所示:
hotspot$1:::object-alloc { self->str_ptr = (char*) copyin(arg1, arg2+1); self->str_ptr[arg2] = '/0'; self->classname = (string) self->str_ptr; @allocs_count[self->classname] = count(); @allocs_size[self->classname] = sum(arg3); } |
(五) hotspot_jni提供者
jni容許java程序與c/c++代碼進行交互。若是你想觀察java代碼與本機代碼的交互,你可使用hotspot_jni提供者。對於每個jni函數輸入/輸出而言,這個提供者將暴露一個探針。
(六) 在java程序中使用dtrace的效果
dtrace被設計爲一種生產模式可觀察性系統(未使用時具備零影響)。當支持探針時,被觀察的系統不受影響。
因爲大部分的由hotspot和hotspot_jni提供者所暴露的jvm探針都是輕量級的,所以能夠用於生產機器中。然而,一些由hotspot提供者所暴露的探針要求使用一個特定的命令行選項"-xx:+extendeddtraceprobes"來啓動jvm。這些探針分別是:java方法入口/方法返回,對象分配和java監視器探針。注意,這些探針都要求改變hotspot字節碼解釋器和hotspot編譯器(字節碼-到-機器代碼編譯器)。即便不被支持時,這些探針的代價也是比較昂貴的。
3、 在java se 6平臺中的可觀察性工具
除了dtrace與java技術的集成以外,java se 6發行中還包含了許多其它的可觀察性工具。下面總結了這些工具,其中還包含一些更爲詳細的連接說明。
(一) jconsole
jconsole使用jvm的可擴展性java管理擴展(jmx)工具來提供關於運行於java平臺的應用程序的性能和資源消耗的信息。
在j2se 5.0軟件中,你須要啓動使用-dcom.sun.management.jmxremote選項監控的應用程序。注意:在java se 6軟件中,再也不有這一要求。當啓動該應用程序時,不須要特定的命令行選項。
在生產系統中的應用
jconsole啓動一個在被觀察的java程序的jvm內部的jmx代理。運行另一部分代碼僅有一點極微弱的影響-可是影響很小。
另外,儘管jconsole在監視本地應用程序的開發和快速原型開發中頗有用,但在實際的應用系統中不推薦使用。理由是,jconsole自己也消耗大量的系統資源。咱們推薦的方法是用遠程監控來把jconsole應用程序與被監控的系統加以隔離。所以,對於應用系統來講,以遠程模式使用jconsole更好些。對於安全的遠程監控來講,可使用安全選項。
(二) jps
jps至關於solaris進程工具ps。更多的信息,請參考《jps-java virtual machine process status tool》。
不象"pgrep java"或"ps -ef | grep java",jps並不使用應用程序名來查找jvm實例。所以,它查找全部的java應用程序,包括即便沒有使用java執行體的那種(例如,定製的啓動器)。另外,jps僅查找當前用戶的java進程,而不是當前系統中的全部進程。
(三) jstat
jstat顯示一個測量(instrumented)java hotspot虛擬機的性能統計信息(請參考《jstat-java virtual machine statistics monitoring tool》)。有關於性能計數器的更詳細的信息請參考《code sample-jvmstat 3.0》。
(四) jstatd
jstatd是一個java遠程方法調用(rmi)服務器應用程序-它監控測量java hotspot虛擬機的建立和終止而且提供一個接口來容許遠程監控工具依附到運行於本地主機的jvm(請參考《jstatd-virtual machine jstat daemon》)。
在應用系統中的使用
jps及其它jvmstat實用程序都使用極爲輕量級的觀察機制。由jvm分配一小部分共享內存,而性能計數器也是從這部份內存中分配的。jvm子系統基於其感興趣的事件更新性能計數器。客戶端工具僅僅負責異步地從共享內存段中進行讀取。所以,總的來講,使用jvmstat進行監控的效果是很小的。
4、 java se 6平臺中針對於postmortem的可觀察性工具 java se 6支持postmortem可觀察性工具-它可以從掛起的java進程或java核心複製中得到信息。這些工具(除了jhat外)都使用solaris libproc庫來依附到和讀取被觀察的程序。在觀察期間,目標程序被掛起。當java進程被掛起或當從一個java進程中發生一個核心複製時,可使用這些工具。在任何可能的狀況下,請考慮使用gcore來捕獲系統的核心複製的一個快照而且使用任何下列工具"離線"分析核心複製。 (一) jinfo jinfo打印一個給定的java進程或核心文件或一個遠程調試服務器的java配置信息。配置信息包括java系統屬性和jvm命令行標誌(更多信息,請參考《jinfo-configuration info》)。 (二) jmap jmap:若是這個工具不使用任何選項(除了pid或core選項)運行,那麼它顯示相似於solaris的pmap工具所輸出的信息。這個工具支持針對java堆可觀察性的若干其它選項。 在java se 6平臺中,新加入了一個-dump選項。這樣可使jmap可以把java堆信息複製到一個文件中,而後咱們可使用新的jhat命令(見下面一節)來分析它。 jmap -dump選項並不使用solaris libproc來實現實時處理;而是,它運行當前正運行的jvm中的一小段代碼,由此來實現堆複製。既然這種堆複製代碼運行於jvm內部,那麼其速度是比較快的。堆複製的效果大體至關於實現一次"徹底的gc"(對整個堆的垃圾收集),再加上把該堆的內容寫入到文件中。實現堆複製的另一種可能的思路是使用gcore來進行核心複製而且運行"jmap -dump"(這與以"離線"方式運行的核心複製造成對照)。 (三) jstack jstack等價於solaris的pstack工具。jstack打印全部的java線程的堆棧跟蹤信息(可選地包括本機幀信息),請參考《jstack-堆棧跟蹤》。關於鎖和死鎖的信息也能夠被打印,請參考java.util.concurrent locks。 (四) jsadebugd jsadebugd依附到一個java進程或核心文件而且擔當一個調試服務器的做用。遠程客戶,例如jstack、jmap和jinfo,都可以經過java rmi依附到該服務器。 (五) jhat jhat是一個java堆複製瀏覽器。這個工具分析java堆複製文件(例如,由上面的"jmap -dump"所產生的)。jhat啓動一個容許堆中的對象在web瀏覽器中進行分析的web服務器。這個工具並非想用於應用系統中而是用於"離線"分析。"jhat工具是平臺獨立的",其意思是,它能夠被用來觀察在任何平臺上所產生的堆複製。例如,咱們有可能在linux系統上使用jhat來觀察一個在solaris os上所產生的堆複製。