java進(jìn)程遠(yuǎn)程調(diào)試

前言

一直以來(lái),產(chǎn)線環(huán)境的問(wèn)題總是很棘手。由于數(shù)據(jù)集、業(yè)務(wù)狀態(tài)、壓力規(guī)模等問(wèn)題,很難在開(kāi)發(fā)環(huán)境進(jìn)行模擬。即使可以建立鏡像的環(huán)境用來(lái)調(diào)試成本也是高昂的,這主要體現(xiàn)在建立這個(gè)環(huán)境所使用的時(shí)間,以及保持問(wèn)題跟進(jìn)需要耗費(fèi)的時(shí)間和人力成本上,這里面服務(wù)器資源很多時(shí)候卻不是最重要的雖然很多時(shí)候也很貴。所以,可靠的手段,除了前段時(shí)間我動(dòng)腦筋的日志體系以外,遠(yuǎn)程進(jìn)程的調(diào)試變成了一個(gè)像瑞士軍刀一樣的存在。有了它我基本上就有了跟蹤所有問(wèn)題的決心。介紹完背景后,開(kāi)始聊正事吧。

怎么遠(yuǎn)程調(diào)試

遠(yuǎn)程調(diào)試其要點(diǎn)主要是這樣幾點(diǎn):

  • 調(diào)試:首先它是jvm的調(diào)試狀態(tài)。其實(shí)這點(diǎn)和我們?cè)谶\(yùn)行ide的時(shí)候進(jìn)行調(diào)試沒(méi)有什么區(qū)別,原理也差不多。
  • 遠(yuǎn)程:這里指的遠(yuǎn)程就是不是本機(jī),其實(shí)就是對(duì)一個(gè)進(jìn)程的調(diào)試。這需要遠(yuǎn)程進(jìn)程開(kāi)啟一個(gè)監(jiān)聽(tīng)端口,并且這邊的ide以相應(yīng)的協(xié)議和通信達(dá)成調(diào)試中需要的狀態(tài)一直
  • 對(duì)應(yīng)版本的代碼:這點(diǎn)很重要。并不是說(shuō)我們隨便啟動(dòng)拿一個(gè)代碼就可以和遠(yuǎn)程進(jìn)程進(jìn)行調(diào)試了,需要是其對(duì)應(yīng)版本的。那版本不一致會(huì)出現(xiàn)什么呢?不知道大家有沒(méi)有過(guò)這樣的體驗(yàn)。有的時(shí)候單步調(diào)試,發(fā)現(xiàn)代碼會(huì)被調(diào)試到?jīng)]有代碼的地方,或者到了自己的斷點(diǎn)哪里想要進(jìn)入,結(jié)果卻去了莫名其妙的地方。這個(gè)原因就是,代碼版本不一致,它其實(shí)是按照真實(shí)的代碼進(jìn)行的跳轉(zhuǎn)。而平常你之所以看到是運(yùn)行步驟好像是跟著代碼走的,其實(shí)是因?yàn)槟愕拇a顯示剛好和它的運(yùn)行一致罷了,你那里沒(méi)有代碼它一樣是這樣跳轉(zhuǎn)的。不過(guò),原理性的東西我沒(méi)有詳細(xì)學(xué)習(xí),基本就是這么回事啦。

被調(diào)試進(jìn)程調(diào)整

平常的進(jìn)程是不可以被調(diào)試的,需要用可調(diào)試狀態(tài)啟動(dòng)進(jìn)程才可被調(diào)試。我的命令被改造成了下面這樣:

java -Xms128m -Xmx512m -jar -Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=18001 gz-lamp-web.jar

其中,-jar之后,gz-lamp-web.jar之前的部分是我為遠(yuǎn)程調(diào)試新增的代碼,我們來(lái)看看它們什么意思。

-Xdebug

這個(gè)其實(shí)挺容易猜的,就是我上面說(shuō)的,調(diào)試狀態(tài),這樣啟動(dòng)進(jìn)程就進(jìn)入了調(diào)試狀態(tài)。進(jìn)入了調(diào)試狀態(tài),我們才可以使用調(diào)試的技術(shù)和今晨個(gè)交互

-Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=18001

這個(gè)有些長(zhǎng),但它其實(shí)是一個(gè)參數(shù)。我們從頭來(lái):

-Xrunjdwp

這其實(shí)是這個(gè)參數(shù)的最頂級(jí)的定義,就是運(yùn)行jdwp。什么是jdwp呢?
JDWP 是 Java Debug Wire Protocol 的縮寫,它定義了調(diào)試器(debugger)和被調(diào)試的 Java 虛擬機(jī)(target vm)之間的通信協(xié)議。
所以,開(kāi)啟了這個(gè)通信,才能夠進(jìn)行交互,也就是我們的調(diào)試行為。

transport

通信協(xié)議自然需要知道怎么通信了,所以,transport之后就是通信參數(shù)的定義,也就是被調(diào)試進(jìn)程在通信上唄設(shè)置成了什么樣。

dt_socket

這是指調(diào)試進(jìn)程和被調(diào)試進(jìn)程使用socket的方式進(jìn)行通信。這里還有個(gè)可選參數(shù)是dt_shmem,這是使用共享內(nèi)存的方式進(jìn)行通信。改參數(shù)僅適用于windwos平臺(tái)。

server=y

這個(gè)參數(shù)的字面意思就是是否開(kāi)啟server模式,我們用y設(shè)置成了是。否的的話,將會(huì)以客戶端的形式進(jìn)行調(diào)試。區(qū)別是什么呢?就是真正的程序在哪運(yùn)行。只要記住,只有server才是真正運(yùn)行程序的那個(gè)就可以了。我的這個(gè)設(shè)置就是仍然以服務(wù)端的進(jìn)程為運(yùn)行進(jìn)程,本地的只是調(diào)試客戶端而已。

suspend=n

如果這個(gè)設(shè)置為y,則被調(diào)試進(jìn)程將會(huì)等待,直到有調(diào)試進(jìn)程連接進(jìn)來(lái)才會(huì)繼續(xù)運(yùn)行。很明顯我們不希望它等待,我們希望它繼續(xù)運(yùn)行。

address=18001

這個(gè)理解起來(lái)就比較容易了,這是調(diào)試通信占用的端口。注意不要和進(jìn)程本身占用的其它端口沖突,否則會(huì)啟動(dòng)不起來(lái)。

文檔

這是我逛網(wǎng)頁(yè)的時(shí)候翻到的一篇oracle的官方文檔,似乎有點(diǎn)舊了,不知道有沒(méi)有新的:
https://docs.oracle.com/javase/1.5.0/docs/guide/jpda/conninv.html

調(diào)試進(jìn)程設(shè)置

其實(shí),理解了上面的內(nèi)容,這里就很簡(jiǎn)單了。尤其是,我們有了Idea這樣強(qiáng)大的IDE后,這個(gè)問(wèn)題就更加簡(jiǎn)單了。先上個(gè)圖吧:

配置界面

為了清晰起見(jiàn),我在圖里做了一些說(shuō)明。
首先,這個(gè)創(chuàng)建的是調(diào)試配置而不是項(xiàng)目或者模塊,這個(gè)要搞清楚,是通過(guò)Edit Configeration進(jìn)去的。然后,新建的是Remote配置。右側(cè)的部分,我們選擇的是附加在遠(yuǎn)程JVM上,使用Socket鏈接,地址和端口和被調(diào)試進(jìn)程保持一致,切換焦點(diǎn)后命令行的部分會(huì)被自動(dòng)生成出來(lái),不用我們手動(dòng)管理,如果需要特殊配置的話,記得選擇JDK的版本。最后,選擇你用來(lái)調(diào)試的模塊就好了。當(dāng)你用這個(gè)配置進(jìn)行啟動(dòng)的時(shí)候,就可以正常的進(jìn)入斷點(diǎn)進(jìn)行調(diào)試了。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容