1、測試用例:
- package jvmTest;
-
- import java.lang.management.ManagementFactory;
- import java.lang.management.RuntimeMXBean;
-
- interface interTest{
- void show();
- }
-
- class Base{
- public int a;
-
- public Base(int a) {
- this.a = a;
- }
- }
-
- class A extends Base implements interTest {
- public int b;
- public A(int a,int b) {
- super(a);
- this.b=b;
- }
-
- @Override
- public void show() {
- System.out.println("a->"+a+",b="+b);
- }
- }
-
-
- public class MainTest {
-
- public static void main(String[] args) {
- String s="shl";
- String[] s2={"shl","abc","bcd"};
- A a=new A(1,2);
- a.show();
- while (true){
- try {
- System.out.println(getProcessID());
- Thread.sleep(600*1000);
- } catch (Exception e) {
-
- }
- }
- }
-
- public static final int getProcessID() {
- RuntimeMXBean runtimeMXBean = ManagementFactory.getRuntimeMXBean();
- System.out.println(runtimeMXBean.getName());
- return Integer.valueOf(runtimeMXBean.getName().split("@")[0])
- .intValue();
- }
- }
執行main方法後就可從控制檯獲取進程ID。
2、Java Threads窗口
進入JAVA_HOME的lib目錄下,在命令行執行java -cp ./sa-jdi.jar sun.jvm.hotspot.HSDB就可喚起HSDB的圖形界面,點擊File-》Attach to Hotspot Process,輸入進程ID,點擊OK,
第一次使用時會報錯,如下圖:
這時將jdk/jre/bin目錄下的sawindbg.dll拷貝到該目錄下即可,重啓,attach成功後進入如下界面:
該界面顯示了當前Java進程下的幾個子線程,main線程就是執行main方法的用戶線程,另外5個是JVM自身使用的線程,選中main線程,上述的5個按鈕就都可以點擊了,第一個按鈕Inspect Thread是查看選中的線程對應的java.lang.Thread對象,如下圖:
可以層層展開查看該對象的各屬性,也可改變地址框中的對象地址,查看特定引用對象的屬性
第二個按鈕Stack Memery是查看當前線程的調用棧的內存,如下圖所示:
一共有3列,第一列是虛擬內存地址,第二列是該內存地址上的數據,以字寬爲單位,64位CPU下就是8字節,即以該地址爲起始往後8字節的數據,第三列是對內存數據的註釋,同顏色的豎線表示範圍,橫線或斜線連接範圍與註釋文字,Interpreted frame表示一個調用棧幀,第一個對應sleep方法的調用棧幀,第二個對應main方法的調用棧幀,最下面的是main方法創建的局部變量的地址,比較奇怪的是代碼中只創建了一個String[],這裏卻有兩個ObjAarray了?還有一個是main方法的參數String[] args。
第三個按鈕show Java stack trace是顯示當前線程的調用鏈,點擊其中的方法可查看方法的字節碼,如main方法,注意本地方法沒有字節碼所以查看不了,如下圖:
其中pc表示具體的方法字節碼指令地址,將滑塊拖到最下面點擊Constant Pool,可以查看常量池中的具體內容,如下:
第四個按鈕Show thread infomation可用於查看指定線程的信息,如下圖:
State是線程的狀態,Stack in use是線程調用棧佔用的內存的起始地址,Base of Stack是調用棧的基地址,Last_Java_SP是調用棧的當前棧幀的棧頂地址,Last_Java_SP表示調用棧的當前棧幀的棧基地址,Last_Java_PC是上一次執行的字節碼指令的地址。
最後一個按鈕find crashes是查找崩潰的線程。
3、Tools 選項
- Class Browser用於查看類,需要用完整的類名的來查詢,如下圖:
@後面就該該類的類型信息或者方法的字節碼指令的內存地址,點擊搜索結果,可以查看該類的繼承關係,方法列表,屬性列表,點擊方法可查看字節碼,拉到底部可查看該類的常量池,如下圖:
- Code Viewer可根據內存地址查看該地址的Kclass信息或者Method信息或者字節碼指令信息,如下圖:
- Computes Reserves ptrs 用於執行反向指針的分析,所謂反向指針是指根據對象地址查找指向該對象的引用的地址。
- Deadlock Detection 用於死鎖檢測
- Find Object by Query 用於通過對象查詢語言查詢對象,使用不方便,可參考:JVM 對象查詢語言(OQL)
- Find Pointer 查找指針
- Find value in heap 在堆內存中查找值,輸入查找的起始地址,返回堆中保存的對象信息
- Find value in CodeCache 在代碼緩存中查找值
- Heap Paramters 顯示年輕代和老年代的內存地址範圍,如eden區有三個值,分別表示起始內存地址,當前已經分配的內存地址和可分配的最大內存地址,如下圖:
- Inspector 對象探視器,輸入對象的內存地址,可查看該對象的所有屬性信息,如下圖:
- Memory Viewer: 內存信息
- Monitor Cache Dump:查看當前進程使用的ObjectMonitor(用於synchronized 同步)的情況,如下圖:
- Object Histogram: 對象直方圖,即所有對象的對象數量及其佔用的內存空間的統計,可搜索指定類,如下圖:
- Show System Properties:顯示系統屬性
- Show VM Version:顯示 VM 版本
- Show –XX flags:顯示 VM 選項
4、windows選項
windows選項下包含兩個,console和Debugger console,前者是hsdb命令行控制檯,後者是hsdb自身調試用的控制檯。前者實際是調用了hsdb的命令行版本CLHSDB,提供了更豐富強大靈活的命令,輸入help,查看所有的命令:
二、CLHSDB
進入JAVA_HOME的lib目錄下,在命令行執行java -cp ./sa-jdi.jar sun.jvm.hotspot.CLHSDB就可喚起CLHSDB的命令行界面了,執行attach 進程ID可attach到本地或者遠程的java進程,採用跟HSDB同樣的測試用例。
1、threads和thread
輸入threads可以查看所有的子線程,輸入thread 線程id可以查看該線程的詳情
第一行Thread 1 Address是Thread實例的地址。
2、classes和class
classes是列出已經加載的所有的類的類型信息,class 完整類名是查找該類的類型信息,如下圖:
3、inspect
同圖形界面的Inspect,用於查看指定地址的類(C++的類)的各屬性信息,如下圖:
4、 jstack
jstack用於查看是否存在死鎖,查看所有線程的調用棧,加上-v選項可以輸出詳細的內存地址信息,如下圖:
5、universe
universe同圖形界面中的Heap Paramters選項,顯示年輕代和老年代堆內存的地址範圍,如下圖:
6、scanoops
用於在指定地址範圍內搜索所有指定類型的所有實例(Oop),後跟起始地址和類型信息,然後通過inspect 可查看具體的實例屬性,如下圖:
7、revptrs
revptrs可根據對象地址查看引用該對象的活躍對象的地址,這裏的引用是指通過類全局屬性而非局部變量引用,修改上述測試用例在類A中增加一個私有屬性,private Base ba=new Base(1);,然後依次執行universe,scanoops,revptrs,inspect命令,如下圖:
8、mem
mem命令可查看指定起始地址和以位寬爲單位的長度的內存的數據,64位CPU的位寬是8字節,如下圖:
A實例的內存大小是24字節,依次是8字節的對象頭,4字節的屬性a,4字節的指向Kclass的壓縮指針,4字節的指向Base實例的壓縮指針,4字節的屬性b。
其他命令可參考OpenJDK 下hotspot/agent/src/share/sun/jvm/hotspot/CommandProcessor的實現。
9、print
輸入一個Klass*, Method*的地址,可以打印該類或者方法,效果等同於Code Viewer選項,如下圖:
10、where
通過threads可查看所有的線程,輸入線程id,查看該線程的調用棧,輸入-a,查看所有線程的調用棧,如下圖:
11、printas
後跟一個Hotspot Type和地址,會打印該Type對象的各屬性,效果同inspect命令,不過不侷限與oop,也可以是對象的真實地址。如下圖:
12、printstatics
printstatics 可以用於獲取Hotspot 定義的C++類的靜態屬性,如表示Java堆內存的Universe對象,如下圖:
13、printmdo
printmdo用於打印指定地址的MethodData對象,該對象保存了Profile統計的方法性能的數據,如下圖: