IntelliJIDEA遠程調試的方法是什么

本篇內容主要講解“IntelliJ IDEA遠程調試的方法是什么”,感興趣的朋友不妨來看看。本文介紹的方法操作簡單快捷,實用性強。下面就讓小編來帶大家學習“IntelliJ IDEA遠程調試的方法是什么”吧!

創(chuàng)新互聯(lián)公司是一家專注于成都做網站、成都網站設計與策劃設計,果洛州網站建設哪家好?創(chuàng)新互聯(lián)公司做網站,專注于網站建設十載,網設計領域的專業(yè)建站公司;建站業(yè)務涵蓋:果洛州等地區(qū)。果洛州做網站價格咨詢:18982081108

實戰(zhàn) IDEA 調試技巧

如果你是做 Java 開發(fā)的,相信你不會沒有聽過 IntelliJ IDEA ,和大多數 Java 開發(fā)者一樣,我一開始的時候也是用 Eclipse 來進行開發(fā),但是自從換了 IDEA 之后,就再也離不開它了,徹底變成了 IDEA 的忠實粉絲(不好意思,打一波廣告。。)。

不得不說,JetBrains 這家來自捷克的軟件公司真的是良心企業(yè),所出產品皆是精品,除了 IDEA,還有 WebStorm,PhpStorm,PyCharm 等,風格都是很類似的,一些類似的快捷鍵包括調試技巧也是通用的。

打開 IDEA 的調試面板,如下圖所示,可以大致的將其分成五個部分:

  • 單步跟蹤

  • 斷點管理

  • 求值表達式

  • 堆棧和線程

  • 變量觀察

IntelliJ IDEA遠程調試的方法是什么

1.1 單步跟蹤

說起調試,估計很多人第一反應就是對程序進行一步一步的跟蹤分析,其實 IDEA 提供了很多快捷鍵來幫助我們跟蹤程序,大抵可以列出下面幾個技巧:

  • Show Execution Point

調試時往往需要瀏覽代碼,對代碼進行分析,有時候在瀏覽若干個源文件之后就找不到當前執(zhí)行到哪了,可能很多人會使用 Navigate Back 來返回,雖然也可以返回去,但可能需要點多次返回按鈕,相對來說使用這個技巧快速定位到當前調試器正在執(zhí)行的代碼行要更簡便。

  • Step Over

這是最基本的單步命令,每一次都是執(zhí)行一行代碼,如果該行代碼有方法會直接跳過,可以說真的是一步一個腳印。

  • Step In / Force Step In

Step Over 會跳過方法的執(zhí)行,可以觀察方法的返回值,但如果需要進到方法里面,觀察方法的執(zhí)行細節(jié),則需要使用 Step In 命令了。另外,Step In 命令也會跳過 jdk 自帶的系統(tǒng)方法,如果要跟蹤系統(tǒng)方法的執(zhí)行細節(jié),需要使用 Force Step In 命令。

關于單步的時候忽略哪些系統(tǒng)方法,可以在 IDEA 的配置項 Settings -> Build, Execution, Deployment -> Debugger -> Stepping 中進行配置,如下圖所示。

IntelliJ IDEA遠程調試的方法是什么

  • Step Out

當使用 Step In 命令跟蹤到一個方法的內部時,如果發(fā)現自己不想繼續(xù)調這個方法了,可以直接把這個方法執(zhí)行完,并停在調用該方法的下一行位置,這就是 Step Out 命令。

  • Drop to Frame

這一招可以說是調試器的一大殺器。在單步調試的時候,如果由于粗心導致單步過了頭,沒有看到關鍵代碼的執(zhí)行情況,譬如想定位下某個中間變量的值,這個時候如果能回到那行關鍵代碼再執(zhí)行一遍就好了,Drop to Frame 就提供了我們這個能力,它可以回到方法調用的地方(跟 Step Out 不一樣,Step Out 是回到方法調用的下一行),讓我們可以再調試一次這個方法,這一次可不要再粗心了。

Drop to frame 的原理其實也非常簡單,顧名思義,它將堆棧的最上面一個棧幀刪除(也就是當前正在執(zhí)行的方法),讓程序回到上一個棧幀(父方法),可以想見,這只會恢復堆棧中的局部變量,全局變量無法恢復,如果方法中有對全局變量進行操作的地方,是沒有辦法再來一遍的。

  • Run to Cursor / Force Run to Cursor

這兩個命令在需要臨時斷點時非常有用,譬如已經知道自己想分析哪一行代碼了,但又不需要下很多無謂的斷點,可以直接使用該命令執(zhí)行到某行,Force Run to Cursor 甚至可以無視所有斷點,直接到達我們想分析的地方。

1.2 斷點管理

斷點是調試器的基礎功能之一,可以讓程序暫停在需要的地方,幫助我們進行分析程序的運行過程。在 IDEA 中斷點管理如下圖所示,合理使用斷點技巧可以快速讓程序停在我們想停的地方:

IntelliJ IDEA遠程調試的方法是什么

可以將斷點分成兩種類型:行斷點指的是在特定的某行代碼上暫停下來,而全局斷點是在某個條件滿足時停下來,并不限于停在固定的某一行,譬如當出現異常時暫停程序。

1.2.1 行斷點
  • Suspend (All / Thread)

  • Condition

條件斷點。這應該也是每個使用調試器的開發(fā)者都應該掌握的一個技巧,當遇到遍歷比較大的 List 或 Map 對象時,譬如有 1000 個 Person 對象,你不可能每個對象都調一遍,你可能只想在 person.name = 'Zhangsan' 的時候讓斷點斷下來,就可以使用條件斷點,如下圖所示:

IntelliJ IDEA遠程調試的方法是什么

  • Log message to console

  • Evaluate and log

當看到上面的 Suspend 這個選項的時候有的人可能會感到奇怪,我下一個斷點不就是為了讓程序停下來嗎?還需要這個選項干什么?是不是有點多余?難道你下個斷點卻不想讓程序停下來?

在發(fā)現 Evaluate and log 這個技巧之前,我對這一點也感覺很奇怪,直到有一天我突然發(fā)現 Suspend Off + Evaluate and log 的配合真的是太有用了。前面有講過,不要把 System.out.println 當作調試手段,因為你完全可以用這個技巧來打印所有你想打印的信息,而不需要修改你的源代碼。

  • Remove once hit

一次性斷點。上面介紹的 Run to Cursor 就是一次性斷點的例子。

  • Instance filters

  • Class filters

  • Pass count

這幾個我用的不是很多,但應該也是非常有用的技巧可以先記下來。在 IDEA 里每個對象都有一個實例ID,Instance filters 就是用于當斷點處代碼所處的實例和設定ID匹配則斷下來。Pass count 則是在斷點執(zhí)行到第幾次的時候暫停下來。

1.2.2 全局斷點
  • Exception breakpoints

  • Method breakpoints

  • Field watchpoints

個人感覺這幾個技巧都不是很常用,感興趣的同學自己實驗一把吧。

1.3 求值表達式

在一堆單步跟蹤的按鈕旁邊,有一個不顯眼的按鈕,這個按鈕就是 “求值表達式”。它在調試的時候很有用,可以查看某個變量的值,也可以計算某個表達式的值,甚至還可以計算自己的一段代碼的值,這分別對應下面兩種不同的模式:

  • 表達式模式(Expression Mode)

  • 代碼片段模式(Code Fragment Mode)

這兩個模式類似于 Eclipse 里面的 Expression View 和 Display View。在 Display View 里也可以編寫一段代碼來執(zhí)行,確實非常強大,但是要注意的是,這里只能寫代碼片段,不能自定義方法,如下圖:

IntelliJ IDEA遠程調試的方法是什么

1.4 堆棧和線程

這個沒什么好說的,一個視圖可以查看當前的所有線程,另一個視圖可以查看當前的函數堆棧。在線程視圖里可以進行 Thread dump,分析每個線程當前正在做什么;堆棧視圖里可以切換棧幀,結合右邊的變量觀察區(qū),可以方便的查看每個函數里的局部變量和參數。

  • 線程視圖

  • 堆棧視圖

IntelliJ IDEA遠程調試的方法是什么

1.5 變量觀察

變量區(qū)和觀察區(qū)可以合并在一起,也可以分開來顯示(如下圖所示),我比較喜歡分開來顯示,這樣局部變量、參數以及靜態(tài)變量顯示在變量區(qū),要觀察的表達式顯示在觀察區(qū)。

觀察區(qū)類似于求值表達式中的 Expression mode,你可以添加需要觀察的表達式,在調試的時候可以實時的看到表達式的值。變量區(qū)的內容相對是固定的,隨著左邊的棧幀調整,值也會變得不同。在這里還可以修改變量原有的值。

IntelliJ IDEA遠程調試的方法是什么

二、使用 jdb 命令行調試

相信很多人都聽過 gdb,這可以說是調試界的鼻祖,以前在學習 C/C++ 的時候,就是使用它來調試程序的。和 gdb 一樣,jdb 也是一個命令行版的調試器,用于調試 Java 程序。而且 jdb 不需要安裝下載,它是 JDK 自帶的工具(在 JDK 的 bin 目錄中,JRE 中沒有)。IDEA更多玩法:IntelliJ IDEA內容聚合

每研究一項新技術,我總是會看看有沒有命令行版本的工具可以替代,在命令行下進行操作給人一種踏實的感覺,每一個指令,每一個參數,都清清楚楚的擺在那里,這相比較于圖形界面的工具,可以學習更深層的知識,而不是把技術細節(jié)隱藏在圖形界面之后,你可以發(fā)現命令行下的每一個參數,每一個配置,都是可以學習的點。

2.1 jdb 基本命令

在 jdb 中調試 Java 程序如下圖所示,直接使用 jdb Test 命令加載程序即可。

IntelliJ IDEA遠程調試的方法是什么

運行完 jdb Test 命令之后,程序這時并沒有運行起來,而是停在那里等待進一步的命令。這個時候我們可以想好在哪里下個斷點,譬如在 main() 函數處下個斷點,然后再使用 run 命令運行程序:

> stop in Test.main正在延遲斷點Test.main。將在加載類后設置。> run運行Test設置未捕獲的 java.lang.Throwable設置延遲的未捕獲的 java.lang.Throwable>VM 已啟動:設置延遲的斷點:Test.main

可以看出在執(zhí)行 run 命令之前,程序都還沒有開始運行,這個時候的斷點叫做“延遲斷點”,當程序真正運行起來時,也就是 JVM 啟動的時候,才將斷點設置上。除了 stop in Class.Method 命令,還可以使用 stop at Class:LineNumber 的方式來設置斷點。

main[1] stop at Test:25

在 jdb 中下斷點,就沒有 IDEA 中那么多名堂了,什么條件斷點,什么 Instance filters 都不支持,只能乖乖的一步一步來。在斷點處,可以使用 list 命令查看斷點附近的代碼,或者用 step 命令單步執(zhí)行,print 或者 dump 打印變量或表達式的值,locals 命令查看當前方法中的所有變量,cont 命令繼續(xù)執(zhí)行代碼。

還有一些其他的命令就不多做介紹了,可以使用 help 查看所有的命令清單,或者參考 jdb 的官方文檔。IDEA更多玩法:IntelliJ IDEA內容聚合

2.2 探索 class 文件結構

在 jdb 中調試 Java 程序時,有可能源代碼文件和 class 文件不在一起,這個時候需要指定源碼位置:

# jdb -sourcepath path/to/source Test

如果不指定源碼位置,在使用 list 命令時會提示找不到源碼文件,如果真的沒有源碼文件,那么在 jdb 里完全就是瞎調了。我們知道 Java 代碼在執(zhí)行的時候,是以字節(jié)碼的形式運行在 JVM 里的,可以猜測到,class 文件中必然有著和源碼相關聯(lián)的一些信息,類似于 C/C++ 語言的 obj 文件一樣,要不然 list 命令怎么可以顯示出當前正在執(zhí)行的代碼是哪一行呢?我們可以使用開源的 jclasslib 軟件查看 class 文件里的內容,一個標準的 class 文件包含了下面這些信息:

  • 基本信息

  • 常量池

  • 接口

  • 屬性

  • 父類

  • 字段

  • 方法

  • Code 屬性

  • 行號屬性

  • 局部變量表

如下圖所示,其中最重要的一個部分就是 Code 屬性,Code 屬性下面有行號屬性 LineNumberTable,這個 LineNumberTable 就是調試器用來關聯(lián)字節(jié)碼和源代碼的關鍵。關于 class 文件,可以參考:

http://ginobefunny.com/post/deep_in_jvm_notes_part4/

IntelliJ IDEA遠程調試的方法是什么

題外話:沒有源碼時如何調試?

如果沒有源碼,雖然在 jdb 里也可以用 step 來單步,但是沒有辦法顯示當前正在運行的代碼,這簡直就是盲調。這個時候只能使用字節(jié)碼調試工具了,常見的字節(jié)碼調試器有:Bytecode Visualizer、JSwat Debugger、Java ByteCode Debugger (JBCD) 等等,參考:

https://reverseengineering.stackexchange.com/questions/7991/java-class-bytecode-debugger

三、關于遠程調試

通過對 jdb 的學習,我們已經越來越接近 Java 調試器的真相了,但是還差最后一步。讓我們先看看 Java 程序在 IDEA 里是如何被調試的,如果你有很強的好奇心,那么在 IDEA 里調試程序的時候可能已經發(fā)現了下面的秘密:

IntelliJ IDEA遠程調試的方法是什么

或者在調試 tomcat 的時候,也有類似的一串仿佛魔咒一般的參數:

IntelliJ IDEA遠程調試的方法是什么

這串魔咒般的參數像下面這樣,一旦你理解了這串參數,你也就打破了 Java 調試器的魔咒,然后才能認識到 Java 調試器真正的面目:

"C:\Program Files\Java\jdk1.8.0_111\bin\java" -agentlib:jdwp=transport=dt_socket,address=127.0.0.1:20060,suspend=y,server=n FooConnected to the target VM, address: '127.0.0.1:20060', transport: 'socket'

這里面有兩個關鍵點:

  • Java 程序在運行的時候帶著 -agentlib 參數,這個參數用于指示 JVM 在啟動時額外加載的動態(tài)庫文件,-agentlib 參數和 -javaagent 不一樣,這個庫文件應該是由 C/C++ 編寫的原生程序(JNI),類似于這里的 jdwp,在 Windows 上對應一個 jdwp.dll 庫文件,在 Linux 上對應 jdwp.so 文件。那么這個 jdwp 庫文件到底是做什么的呢?它后面的一串參數又是什么意思?

  • jdwp 的參數里貌似提到了 socket,并有 address=127.0.0.1:20060 這樣的 IP 地址和端口號,而且下面的 Connected to the target VM 也似乎表示調試器連接到了這么一個網絡地址,那么這個地址到底是什么呢?由于這里是本地調試,所以 IP 地址是 127.0.0.1 ,那么如果是遠程調試的話,是不是這里也是支持的呢?

在 IDEA 的 Run/Debug Configuration 配置頁面,你也可以添加一個遠程調試,界面如下圖,可以發(fā)現上面那串魔咒參數又出現了:

IntelliJ IDEA遠程調試的方法是什么

在真正開始遠程調試之前,我們不妨帶著這些疑問,來學習 Java 調試器的基本原理。IDEA更多玩法:IntelliJ IDEA內容聚合

四、Java 調試原理及 JPDA 簡介

在武俠世界里,天下武功可以分為兩種:一種講究招式新奇,出招時能出其不意,善于利用兵器的特性和自身的高妙手法攻敵不備;另一種講究內功心法,就算是最最普通的招式,結合自身的深厚內力,出招時也能有雷霆之勢。其實在技術的世界里,武功也可以分為兩種:技巧和原理。

上面講的那么多,無論你是掌握了 IDEA 的所有調試技巧也好,還是記熟了 jdb 的所有命令也好,都只是招式上的變化,萬變不離其宗,我們接下來就看看調試器的內功心法。

4.1 JPDA

我們知道,Java 程序都是運行在 JVM 上的,我們要調試 Java 程序,事實上就需要向 JVM 請求當前運行態(tài)的狀態(tài),并對 JVM 發(fā)出一定的指令,或者接受 JVM 的回調。為了實現 Java 程序的調試,JVM 提供了一整套用于調試的工具和接口,這套接口合在一起我們就把它叫做 JPDA(Java Platform Debugger Architecture,Java 平臺調試體系)。

這個體系為開發(fā)人員提供了一整套用于調試 Java 程序的 API,是一套用于開發(fā) Java 調試工具的接口和協(xié)議。本質上說,它是我們通向虛擬機,考察虛擬機運行態(tài)的一個通道,一套工具。

JPDA 由三個相對獨立的層次共同組成,而且規(guī)定了它們三者之間的交互方式。這三個層次由低到高分別是 Java 虛擬機工具接口(JVMTI),Java 調試線協(xié)議(JDWP)以及 Java 調試接口(JDI),如下圖所示(圖片來自 IBM developerWorks):

IntelliJ IDEA遠程調試的方法是什么

這三個模塊把調試過程分解成幾個很自然的概念:調試者(debugger)和被調試者(debuggee),以及他們中間的通信器。被調試者運行于我們想調試的 Java 虛擬機之上,它可以通過 JVMTI 這個標準接口,監(jiān)控當前虛擬機的信息;調試者定義了用戶可使用的調試接口,通過這些接口,用戶可以對被調試虛擬機發(fā)送調試命令,同時調試者接受并顯示調試結果。

在調試者和被調試者之間,調試命令和調試結果,都是通過 JDWP 的通訊協(xié)議傳輸的。所有的命令被封裝成 JDWP 命令包,通過傳輸層發(fā)送給被調試者,被調試者接收到 JDWP 命令包后,解析這個命令并轉化為 JVMTI 的調用,在被調試者上運行。類似的,JVMTI 的運行結果,被格式化成 JDWP 數據包,發(fā)送給調試者并返回給 JDI 調用。而調試器開發(fā)人員就是通過 JDI 得到數據,發(fā)出指令。

詳細的內容,可以參考

https://www.ibm.com/developerworks/cn/java/j-lo-jpda1/index.html

4.2 Connectors & Transport

到這里,我們已經知道了 jdwp 是調試器和被調試程序之間的一種通信協(xié)議。不過命令行參數 -agentlib:jdwp=transport=dt_socket,address=127.0.0.1:20060,suspend=y,server=n 中的 jdwp 貌似還不止于此。

事實上,這個地方上 jdwp.dll 庫文件把 JDI,JDWP,JVMTI 三部分串聯(lián)成了一個整體,它不僅能調用本地 JVMTI 提供的調試能力,還實現了 JDWP 通信協(xié)議來滿足 JVMTI 與 JDI 之間的通信。

想要完全理解這串參數的意思,我們還需要學習兩個概念:Connectors(連接器)和 Transport(傳輸)。

常見的連接器有下面 5 種,它指的是 JDWP 建立連接的方式:

  • Socket-attaching connector

  • Shared-memory attaching connector

  • Socket-listening connector

  • Shared-memory listening connector

  • Command-line launching connector

其中 attaching connector 和 listening connector 的區(qū)別在于到底是調試器作為服務端,還是被調試程序作為服務端。

傳輸指的是 JDWP 的通信方式,一旦調試器和被調試程序之間建立起了連接,他們之間就需要開始通信,目前有兩種通信方式:Socket(套接字) 和 Shared-memory(共享內存,只用在 Windows 平臺)。

4.3 實戰(zhàn)遠程調試

通過上面的學習我們了解到,Java 調試器和被調試程序是以 C/S 架構的形式運行的,首先必須有一端以服務器的形式啟動起來,然后另一段以客戶端連接上去。如果被調試程序以服務端運行,必須加上下面的命令行參數:

# java -agentlib:jdwp=transport=dt_socket,server=y,address=5005 Test# java -agentlib:jdwp=transport=dt_shmem,server=y,address=javadebug Test

第一句是以 socket 通信方式 來啟動程序,第二句是以 共享內存 的方式來啟動程序,socket 方式需要指定一個端口號,調試器通過該端口號來連接它,共享內存方式需要指定一個連接名,而不是端口號。

在程序運行起來之后,可以使用 jdb 的 -attach 參數將調試器和被調試程序連接起來:

# jdb -attach 5005# jdb -attach javadebug

在 Windows 平臺上,第一條命令會報這樣的錯:java.io.IOException: shmemBase_attach failed: The system cannot find the file specified,這是由于 jdb -attach 使用系統(tǒng)默認的傳輸來建立連接,而在 Windows 上默認的傳輸是 共享內存 。要想在 Windows 上使用 socket 方式來連接,要使用 jdb -connect 命令,只是命令的參數在寫法上不太好記憶:

# jdb -connect com.sun.jdi.SocketAttach:hostname=localhost,port=5005# jdb -connect com.sun.jdi.SharedMemoryAttach:name=javadebug

如果反過來,想讓調試器以服務端運行,執(zhí)行下面的命令:

# jdb -listen javadebug

然后 Java 程序通過下面的參數來連接調試器:

# java -agentlib:jdwp=transport=dt_shmem,address=javadebug, suspend=y Test# java -agentlib:jdwp=transport=dt_socket,address=127.0.0.1:5005,suspend=y,server=n

最后我們再回過頭來看一看 IDEA 打印出來的這串魔咒參數,可以大膽的猜測,IDEA 在調試的時候,首先以服務器形式啟動調試器,并在 20060 端口監(jiān)聽,然后 Java 程序以 socket 通信方式連接該端口,并將 JVM 暫停等待調試。

"C:\Program Files\Java\jdk1.8.0_111\bin\java" -agentlib:jdwp=transport=dt_socket,address=127.0.0.1:20060,suspend=y,server=n FooConnected to the target VM, address: '127.0.0.1:20060', transport: 'socket'

到此,相信大家對“IntelliJ IDEA遠程調試的方法是什么”有了更深的了解,不妨來實際操作一番吧!這里是創(chuàng)新互聯(lián)網站,更多相關內容可以進入相關頻道進行查詢,關注我們,繼續(xù)學習!

當前文章:IntelliJIDEA遠程調試的方法是什么
文章網址:http://bm7419.com/article20/jdiico.html

成都網站建設公司_創(chuàng)新互聯(lián),為您提供電子商務、網站內鏈外貿網站建設、網站設計公司、網站導航、品牌網站制作

廣告

聲明:本網站發(fā)布的內容(圖片、視頻和文字)以用戶投稿、用戶轉載內容為主,如果涉及侵權請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內容未經允許不得轉載,或轉載時需注明來源: 創(chuàng)新互聯(lián)

商城網站建設