Jconsole的使用及對java內存池的專業術語理解

最近需要參與一些java程序debug和性能調整方面的工作,jconsole是jdk自帶的工具,比較好用,以下文章前面大部分翻譯自:http://java.sun.com/j2se/1.5.0/docs/guide/management/jconsole.html ,後面關於用戶名/密碼和使用ssl加密連接的部分是從其他地方蒐集的資料並且進行了驗證。

Jconsole簡介:

Jconsole是一個JMX兼容的監視工具。它使用Java虛擬機的JMX機制來提供運行在Java平臺的應用程序的性能與資源耗費信息。

開始jconsole

Jconsole應用程序位於JDK_HOME/bin目錄下。

命令語法:

可以使用jconsole監視本地應用程序和遠程應用程序。

注意:在開發階段或者原型階段,使用jconsole監視本地應用程序是很有用的,但是不建議在生產環境中使用,因爲jconsole本身也將顯著的消耗系統資源。推薦使用遠程監視來將jconsole和被監視平臺孤立開。查看jconsole詳細語法:jconsole - Java Monitoring and Management Console.

本地監視:

如果需要監控本地應用程序,那麼啓動jconsole使用的用戶id必須和被監視程序的用戶id一致。啓動本地監控的命令語法如下:

Jconsole [processed]

得到進程號(PID)的辦法:

Unix/Linux:使用ps查看java進程的PID

Windows:任務管理器查看java或者javaw進程的PID

也可以使用jps命令行工具 查看PIDs

例子:如果你發現notepad.jar應用程序的PID爲2956,則可以通過如下命令啓動jconsole:

jconsole 2956

jconsole和被監視的應用程序必須是使用同一個用戶運行的。管理和監視系統使用操作系統的文件權限。

如果你沒有指定PID,jconsole會自動的探測出本地運行的所有java應用程序並顯示一個對話框讓你選擇你想監控的程序(見下一節)

詳細信息見:Local JMX Monitoring and Management.

遠程監視:

使用如下命令啓動jconsole進行遠程監視:

jconsole [hostname:portNum]

Hostname是被監控系統主機名,portNum是當你啓動JVM,打開JMX代理之後指定的端口號。詳細信息見:Remote JMX Monitoring and Management.

如果你沒有指定主機名/端口號,那麼jconsole會顯示一個連接對話框(見下一節)來輸入主機名和端口號。

連接JMX代理:

如果在啓動jconsole的時候指定了要連接的JMX代理,它會自動的啓動對指定JVM的監視。任何時候如果你想連接到另外一臺主機,可以選擇:Connection | New Connection並輸入連接信息。

或者如果你沒有輸入代理,那麼啓動jconsole之後會出現連接對話框,對話框有三個tab頁:

Local

Remote

Advanced

Local選項卡

clip_image002

Local選項卡列出了在本地系統上,使用與啓動jconsole相同的用戶運行的JVM及其PID、類/參數信息。選擇需要堅實的應用程序,然後點擊Connect

Remote選項卡

clip_image004

要監視遠程JVM,需要輸入:

Host name:遠程主機名

Port number:啓動JVM的時候指定的JMX代理(agent)端口號。

User name and password:使用的用戶名和密碼(僅在通過需要用戶名/密碼的 JMX代理監視JVM時需要)

關於設置JMX代理端口號的詳細信息,見:

Enabling the JMX Management Agent.

關於用戶名和密碼的詳細信息,見:

Using Password and Access Files.

要監視JVM本身使用的JVM,僅需設置主機名爲localhost,端口號爲0,然後點擊Connect即可。

Advanced選項卡

clip_image006

利用Advanced選項卡,你可以通過輸入JMX URL及其用戶名密碼來連接其他JMX代理(MBean Servers),JMX URL的語法在如下鏈接:

javax.management.remote.JMXServiceURL.

注意:如果JMX代理在使用一個未包含在Java平臺中的連接器(connector),你需要在運行jconsole時將connector classes加入到classpath中,如下:

jconsole –J-Djava.class.path=JAVA_HOME/lib/jconsole.jar:JAVA_HOME/lib/tools.jar:connector-path

Jconsole界面:

Jconsole界面由以下六個選項卡組成:

Summary選項卡:顯示JVM和被監視值的彙總信息

Memory選項卡:顯示內存使用信息。

Threads選項卡:顯示線程使用信息。

Classes選項卡:顯示類(class)加載信息。

MBeans選項卡:顯示MBeans信息

VM選項卡:顯示JVM信息。

以下是詳細介紹:

查看彙總信息:

Summary選項卡顯示了關於線程使用、內存消耗和class加載的一些關鍵監視信息,以及JVM和操作系統的信息。

clip_image008

Summary

Uptime:JVM已運行時長。

Total compile time:花費在即時編譯(JIT compilation)中的時間。

Process CPU time:JVM花費的總CPU時間。

Threads

Live threads:當前活動的daemon線程加non-daemon線程數量。

Peak:自JVM啓動後,活動線程峯值。

Daemon threads:當前活動的Daemon線程數量。

Total started:自JVM啓動後,啓動的線程總量(包括daemon,non-daemon和終止了的)

Memory

Current heap size:堆(heap)佔用的內存量,以K爲單位。

Committed memory:爲堆分配的內存總量

Maximum heap size:堆佔用的最大內存量。

Objects pending for finalization:等待析構(finalization)的對象數量。

Garbage collector information:GC信息,擺闊垃圾回收器名稱,已執行的垃圾回收次數和執行垃圾回收總耗時。

Classes

Current classes loaded:當前被加載到內存的classes數量

Total classes loaded:自JVM啓動後被加載到內存的classes總量,包括後來卸載的。

Total classes unloaded:自JVM啓動後,從內存卸載的classes總量。

Operating System:

Total physical memory:物理內存總量

Free physical memory:物理內存空閒量

Committed virtual memory:爲運行中的進程分配的虛擬內存總量

監視內存消耗:

Memory選項卡提供了內存消耗和內存池信息。

clip_image010

以上圖表顯示了JVM的內存使用和時間的對應關係,包括heap和non-heap內存以及指定的(specific)內存池。內存池種類與具體使用的JVM有關,以HotSpot JVM爲例,內存池有:

l Eden Space(heap):大多數對象初始化時從Eden Space池分配內存,即是存在於此池中

l Survivor Space(heap):此池包含的對象是那些原先在eden space中,但是已經經歷過垃圾回收而仍然存在的對象。

l Tenured Generation(heap):在surviver space中已經存在了一段時間之後的對象會移動到這個池中。

l Permanent Generation(non-heap):包含虛擬機自身的所有反射數據。比如class和mothod對象。對於使用class data sharing的JVM,這一代分爲只讀和讀寫兩個區域。

Code Cache (non-heap):HotSpot JVM也包含一個“代碼緩存”,是編譯和存儲本地代碼所佔用的內存。

查看關於內存池的詳細信息:Garbage Collection.

Detail區域顯示了幾種當前內存度量:

Used:當前使用的內存總量。使用的內存總量是指所有的對象佔用的內存,包括可達和不可達的對象。

Committed:JVM可使用的內存量。Committed內存數量可能隨時間變化而變化。JAVA虛擬機可能將某些內存釋放,還給操作系統,committed內存可能比啓動時初始分配的內存量要少。Committed內存總是大於等於used內存。

Max:內存管理可用的最大內存數量。此值可能改變或者爲未定義。如果JVM試圖增加使用內存(used memory)超出了committed內存,那麼即時使用內存小於或者等於最大內存(比如系統虛擬內存較低),內存分配仍可能失敗。

右下角的圖表顯示了內存池在heap和non-heap消耗的內存量。當內存使用超出了內存使用閥值時,柱狀圖會變紅。你可以通過設置MemoryMXBean的一個屬性來調整內存佔用閥值。

Heap and Non-heap內存

JVM管理兩種內存:heap和non-heap內存,兩種內存都是在JVM啓動時建立。

Heap memory 是運行時數據區域,用於JVM爲所有對象實例和隊列分配的內存。Heap可能爲固定植或者可變值。垃圾收集器是一個用於回收對象佔用的heap內存的自動化內存管理系統。

Non-heap memory 包含一個在所有線程共享的方法區域(method area)和內部進程或JVM優化所需的內存。它存儲了每一個類的結構,比如運行常量池,字段和方法數據,構造函數和方法的代碼。方法區域邏輯上是heap的一部分,但是依賴於實現,JVM可能不進行垃圾收集或壓縮。像heap一樣,方法區域可能爲固定或可變大小。方法區域所需要的內存沒有必要是連續的。

除了方法區域之外,一個JVM實現的內部進程或優化所需的內存也屬於non-heap內存。比如JIT編譯器爲了提高性能而用於存儲本地機器碼所需的內存。

內存池和內存管理

內存池(Memory pools)和內存管理器是JVM內存管理系統的關鍵部分

一個內存池(memory pool)代表JVM管理的一塊內存區域。JVM擁有最少一個內存池,JVM在運行中可能創建或刪除內存池。一個內存池可以屬於heap內存或者non-heap內存。

內存管理器(memory manager)管理一個或多個內存池。垃圾回收其是一種負責回收被不可打對象佔用的內存的內存管理器。一個JVM可以擁有一個或者多個內存管理器。JVM在運行中可能增加或刪除內存管理器。一個內存池可以被多於一個內存管理器管理。

垃圾收集:

垃圾收集(GC)是指JVM釋放那些被無引用對象佔用的內存空間。它通常認爲那些有活動引用的對象是“活”對象,而那些沒有引用或不可達的對象爲“死”對象”。垃圾收集是釋放被死對象佔用的內存的過程。GC的算法和參數對性能有巨大的影響。

HotSpot VM垃圾收集器使用 分代垃圾收集(generational garbage collection)。分代GC利用了大多數程序中,從經驗看有如下特點:

很多對象有一個很短的生存期(比如迭代器iterators、本地變量)

某些對象擁有很長的生存期(比如高層持久化對象)

所以,分代的GC將內存劃分爲代(generations)並且賦予每一個內存池。當一代用盡了分配的內存,VM會在那個內存池進行一次局部(partial)的垃圾收集(或者叫minor collection)來收集被死對象佔用的內存。局部垃圾收集比全垃圾收集(full GC)快的多。

HotSpot VM定義了2代:young generation (有時叫做nursery)和old generation。Young generation由一個eden space和兩個survivor spaces組成。最初,VM將所有的對象放入eden space,大多數對象死在那裏~~~,當VM運行了一次minor GC,VM將剩餘的對象從eden space移動到某個survivor space中。然後VM將那些在survivor spaces中生存了足夠長時間的對象移動到位於old generation中的tenured spaces。當tenured spaces滿了以後,將發生一次full GC,full GC涉及到所有存活的對象,因此比較慢。Permanent generation保存了所有的虛擬機自身的反射數據,比如class和method objects

默認情況下代的排列類似於下圖:

clip_image012

如同下文鏈接中說明的,如果垃圾收集器成爲瓶頸,你可以通過自定義代大小來提高性能。使用jconsole可以發現你的性能情況對垃圾收集器參數的敏感程度。詳細情況見:

Tuning Garbage collection with the 5.0 HotSpot VM

監視線程使用:

線程選項卡提供了關於線程使用的信息。

clip_image014

左下角列出的爲所有的活動線程。如果你在過濾(filter)對話框輸入字符串,那麼線程列表將盡顯示那些包含你輸入字符串的線程。在線程列表上點擊線程名,可以顯示在右側顯示縣城信息,包括線程名,狀態和調用堆棧。

圖表顯示了活動線程/時間。有三行內容:

Magenta:線程總數

Red:峯值線程數

Blue:活動線程數。

關於線程、daemon線程詳細信息,請查看鏈接:java.lang.Thread

監視Class加載:

Classes選項卡顯示了關於class loading的信息:

clip_image016

圖表顯示了 類加載/時間

紅線是類加載總數(包括後來卸載的)

藍線表示當前的類加載數量。

選項卡底部的Detail節顯示了自JVM啓動後類加載的總量,當前加載量和卸載量。

監視和管理MBeans:

MBean選項卡顯示了所有在platform. MBean server上註冊的MBeans的信息。

clip_image018

左邊的樹形結構顯示了所有的MBean,按其對象名排序。當在樹種選擇了一個MBean之後,其屬性、操作、通知和其他信息會在右邊顯示。

如果屬性值是可寫的(可寫會藍色顯示),你可以設置屬性值。你也可以調用在操作選項卡中顯示的操作。

顯示圖表:

你可以通過雙擊屬性值的方法顯示一個屬性值/時間圖表,比如,如果你雙擊java.lang.GarbageCollector.Copy Mbean的CollectionTime屬性,你會得到如下圖所示的顯示:

clip_image020

查看VM信息。

VM選項卡提供了JVM的信息。

clip_image022

這些信息包括:

Uptime:JVM啓動後的總時間。

Processes CPU Time:JVM啓動後消耗的總CPU時間。

Total Compile Time:即時編譯(JIT compilation)消耗的總時間。JVM的具體實現決定JIT編譯何時發生。Hotspot VM使用adaptive compilation,在這種方式zhogn ,VM使用標準的解釋器(interpreter)運行一個應用程序,但是會分析其代碼判斷性能瓶頸或者”hot spots”。

配置tomcat使用jconsole

修改catalina腳本

Windows平臺:修改catalina.bat,在dorun和dostart段開頭增加一行(注意是一行):

set JAVA_OPTS=%JAVA_OPTS% -Djava.rmi.server.hostname=192.168.1.101

-Dcom.sun.management.jmxremote

-Dcom.sun.management.jmxremote.port="9004"

-Dcom.sun.management.jmxremote.authenticate="false" -Dcom.sun.management.jmxremote.ssl="false"

Unix/Linux平臺:修改catalina.sh,在dorun和dostart段開頭增加一行(注意是一行):

JAVA_OPTS="$JAVA_OPTS "-Dcom.sun.management.jmxremote

-Dcom.sun.management.jmxremote.port="9004"

-Dcom.sun.management.jmxremote.authenticate="false" -Dcom.sun.management.jmxremote.ssl="false"

啓動jconsole

啓動tomcat之後,根據上文中的jconsole簡介中的命令啓動jconsole,如果是在服務器本地運行jconsole,會出現如下界面:

clip_image023

直接進行連接即可。

如果是遠程監控,需要點擊遠程選項卡並輸入相關信息,示例如下:

clip_image024

“主機名或ip”處填寫需要監視的主機ip,端口爲服務器上上文中添加的-Dcom.sun.management.jmxremote.port="portNumber"設定的端口,本文以9004爲例。在設定爲:-Dcom.sun.management.jmxremote.authenticate="false" 的情況下,用戶名和口令留空即可。

 

如果需要使用JConsole遠程監控 Tomcat可以在命令行直接輸入:

JConsole 192.168.1.101:9004

進階安全設定

在上文中的配置適用於在測試環境中監視tomcat,如果是在生產環境中監視tomcat則需要在安全性上有進一步要求。

配置jmx訪問密碼

1. 修改上文中的catalina腳本中的JAVA_OPT參數,將
-Dcom.sun.management.jmxremote.authenticate="false" 修改爲:
-Dcom.sun.management.jmxremote.authenticate="true"

2. 將$JRE/lib/management/jmxremote.password.template文件在同目錄下複製一份,重命名爲$JRE/lib/management/jmxremote.password,編輯jmxremote.password,添加允許訪問的用戶名及密碼,比如添加用戶zxwh,密碼爲zxme,則在文件尾添加一行:
zxwh zxme
注意用戶密碼不能包含空格,tab等字符

3. 編輯$JRE_HOME/lib/management/jmxremote.access文件,對剛纔添加的用戶賦予一定的權限:
zxwh readonly (或者readwrite)

4. 確認jmxremote.password和jmxremote.access兩個文件中的用戶是相同的。注意如果jmxremote.access中沒有對應用戶的話,配置是無效的。
注:以上配置文件的位置都是可以更改的,具體配置方法在此不再贅述。

5. 由於jmxremote.password中的密碼都是明文保存的,所以jmxremote.password、jmxremote.access文件的權限要注意,應該設置爲只有owner纔可讀,當然這個用戶也必須是啓動tomcat的用戶。

6. 啓動jconsole進行連接,在用戶名和口令處輸入設定的用戶和密碼。

7. 使用密碼認證方式進行連接,不但可以提高安全性,而且可以對用戶的權限進行設置。如果不使用密碼認證的方式,則無法對用戶的權限進行限制。

配置使用ssl進行加密連接

1. 在服務器上使用keytool創建密鑰對
keytool是java平臺自帶的一個密鑰和證書管理工具,使用keytool創建密鑰對:
keytool -genkey -alias tomcat -keystore /somepath/tomcatKeyStore
按照提示輸入相關信息(包括設定密碼、姓、組織名等),這些信息是可以隨便輸入的,但從產品角度講應該統一設定。輸入的密碼在今後操作中均需要使用。

2. 導出公鑰
keytool -export -alias tomcat -keystore /somepath/tomcatKeyStore -file /somepath/jconsole.cert

3. 將公鑰導入至需要運行jconsole的機器。
keytool –import –alias jconsole –keystore /somepath/jconsoleKeyStore -file /somepath/jconsole.cert

4. 修改tomcat的catalina腳本
將-Dcom.sun.management.jmxremote.ssl="false"修改爲:
-Dcom.sun.management.jmxremote.ssl="true",並在 JAVA_OPTS變量行添加:
-Djavax.net.ssl.keyStore=/somepath/jconsoleKeyStore 
-Djavax.net.ssl.keyStorePassword=設定的密碼

5. 使用如下參數啓動jconsole :
jconsole -J-Djavax.net.ssl.trustStore=/somepath/jconsoleKeyStore

6. 填入主機名、用戶、口令連接服務器。

其他問題

1. 在執行shutdown.sh或者shutdown.bat腳本關閉tomcat時出現如下錯誤,tomcat無法關閉:
錯誤: 代理拋出異常: java.rmi.server.ExportException: Port already in use: 9004;
nested exception is:
java.net.BindException: Address already in use: JVM_Bind

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章