<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          Java服務(wù)器調(diào)試指南

          共 3238字,需瀏覽 7分鐘

           ·

          2022-07-27 22:18


          在實(shí)際開發(fā)中,總會(huì)遇到程序啟動(dòng)不起來或者運(yùn)行結(jié)果不符合期望的情況,如果是在本地,直接debug就行了,幾乎人人都會(huì),但是如果到了遠(yuǎn)程,大多數(shù)情況下我們可以看日志,通過日志排查定位到問題,但是如果你的日志不多,或者日志中看不出問題,此時(shí)情況就比較難以處理了,而實(shí)際上我們?nèi)匀豢梢酝ㄟ^debug的形式來解決,只不過由原來的本地在ide中通過GUI來debug變?yōu)橥ㄟ^命令行來debug;


          開啟服務(wù)debug端口

          如果想要對(duì)我們遠(yuǎn)程部署的服務(wù)進(jìn)行debug,那么首先我們要開啟debug端口,開啟方式如下:


          開啟遠(yuǎn)程debug:

          在Java啟動(dòng)命令后追加系統(tǒng)參數(shù)-agentlib:jdwp=transport=dt_socket,server=y,suspend=y,address=8000
          PS:suspend表示是否需要等待遠(yuǎn)程debug連接再開始啟動(dòng),y表示需要等待遠(yuǎn)程debug連接才會(huì)繼續(xù)執(zhí)行;

          開始debug

          當(dāng)我們的服務(wù)啟動(dòng)后,我們就可以開始debug了,此時(shí)有兩種情況:

          • 我們本地可以直接連接到服務(wù)所在的機(jī)器;

          • 我們本地?zé)o法直接連接到服務(wù)所在的機(jī)器;(可能是服務(wù)在容器中、堡壘機(jī)后等)


          如果我們本地可以直接連接到服務(wù)所在的機(jī)器,那么可以在ide中直接選擇遠(yuǎn)程debug,填寫好IP和端口號(hào)即可連接上進(jìn)行遠(yuǎn)程debug,與本地debug的體驗(yàn)基本是一致的,沒什么好講的,我們這里主要說說本地?zé)o法連接到服務(wù)所在的機(jī)器時(shí)如何進(jìn)行debug;



          當(dāng)我們無法連接到遠(yuǎn)程服務(wù)所在的機(jī)器時(shí),此時(shí)可以使用jdk中為我們提供的jdb來調(diào)試,熟悉C語言的可能會(huì)想到gdb,這個(gè)和C語言的gdb是一個(gè)作用,都是用來讓我們調(diào)試程序的;下面我們來介紹jdb的詳細(xì)用法:


          jdb詳細(xì)用法

          在遠(yuǎn)程服務(wù)的主機(jī)上使用jdb命令連接到服務(wù),命令如下(如果jdb所在的機(jī)器與服務(wù)所在機(jī)器不一致,需要將127.0.0.1替換為服務(wù)所在機(jī)器的IP,但是注意需要保證jdb所在的機(jī)器可以通過這個(gè)ip+端口直連到服務(wù)):


          jdb -attach 127.0.0.1:8000



          如果有源碼,可以使用-sourcepath指定源碼,用法與Java指定classpath一致


          jdb -sourcepath /源碼路徑 -attach 127.0.0.1:8000



          使用上述命令進(jìn)入調(diào)試控制臺(tái)后(命令行),我們就可以使用下面這些命令(常用命令)來調(diào)試我們的應(yīng)用了:


          stop at: 在指定地方斷點(diǎn),例如stop at com.joekerouac.Test:10在com.joekerouac.Test的第10行斷點(diǎn);locals:當(dāng)前堆棧中所有本地變量,包含方法入?yún)ⅲㄗ⒁猓翰话绢惖某蓡T變量);step:執(zhí)行當(dāng)前行,如果當(dāng)前行調(diào)用了某個(gè)方法,則進(jìn)入方法;step up:執(zhí)行到當(dāng)前方法結(jié)束;next:與step類似,不同的是如果當(dāng)前行調(diào)用了某個(gè)方法,會(huì)跳過方法而不是進(jìn)入方法;cont:執(zhí)行到下個(gè)斷點(diǎn);up:上移線程棧;down:下移線程棧;print: 打印指定變量值;例如一個(gè)方法有一個(gè)參數(shù)叫num,進(jìn)入方法后可以使用print num來打印num的值;eval:與print類似,不同的是這個(gè)支持使用表達(dá)式;where all:打印當(dāng)前所有線程堆棧;where 線程ID:打印指定線程的堆棧,線程ID可以通過threads獲取;set:修改當(dāng)前某個(gè)變量的值;fields:列出指定類的所有字段;list: 查看當(dāng)前所在調(diào)用棧的源碼;


          可以在調(diào)試控制臺(tái)使用help查看jdb支持的完整命令列表及其說明;




          簡單示例


          1、編寫一個(gè)Test.java用來測試:


          public class Test {
          public static void main(String[] args) { int a = 1; int b = 2; int c = 3; int d = add(a, b, c); int e = add(b, c, d); System.out.println(e); }
          private static int add(int a, int b, int c) { int d = a + b; return d + c; }
          }


          2、編譯

          使用如下命令編譯我們的程序:


          # 注意,這里加了一個(gè)-g選項(xiàng),表示編譯時(shí)攜帶debug信息,否則是沒辦法正常進(jìn)# 行debug的,對(duì)于我們的服務(wù),使用maven編譯時(shí)自動(dòng)開啟了該選項(xiàng),攜帶了debug信# 息,所以我們沒有主動(dòng)指定;javac -g Test.java


          3、運(yùn)行我們的程序

          使用如下命令運(yùn)行我們的程序:


          # 這里我們開啟debug選項(xiàng),并且指定監(jiān)聽8000端口,這個(gè)端口可以自行修改java -agentlib:jdwp=transport=dt_socket,server=y,suspend=y,address=8000 Test


          運(yùn)行后提示如下:


          4、debug連接

          再開一個(gè)shell窗口,在這個(gè)窗口執(zhí)行如下命令進(jìn)行連接:


          # 注意,這里我們運(yùn)行jdb的目錄就是源碼所在目錄,所以源碼目錄使用了當(dāng)前目錄./jdb -sourcepath ./ -attach 127.0.0.1:8000


          運(yùn)行結(jié)果如下:

          5、開始debug


          設(shè)置一個(gè)斷點(diǎn)

          使用如下命令設(shè)置一個(gè)斷點(diǎn):


          # 表示在Test類的第7行打一個(gè)斷點(diǎn),注意,類名要完全限定名,我們這里由于是測試,# 所以并沒有包,也不需要添加包名;stop at Test:7


          結(jié)果如下:


          開始執(zhí)行

          使用cont指令開始執(zhí)行,結(jié)果如下:


          查看源碼

          使用list查看當(dāng)前源碼,結(jié)果如下:

          可以清晰的看到當(dāng)前執(zhí)行到了我們定義的斷點(diǎn)處停止了;


          使用step進(jìn)入方法調(diào)用

          使用step命令進(jìn)入add這個(gè)方法調(diào)用的內(nèi)部,執(zhí)行結(jié)果如下:


          當(dāng)我們使用list查看當(dāng)前斷點(diǎn)上下的源碼時(shí),結(jié)果如下:


          可以看到,當(dāng)前已經(jīng)進(jìn)入方法了(還未執(zhí)行任何行);


          使用locals查看本地變量

          此時(shí)我們可以使用locals來查看本地變量,因?yàn)檫€未執(zhí)行任何一行,所以本地變量中只有三個(gè)方法參數(shù),結(jié)果如下:


          使用step up來結(jié)束方法執(zhí)行

          使用step up前我們的調(diào)用棧處于這個(gè)狀態(tài):


          使用step up后會(huì)直接結(jié)束add方法的執(zhí)行,跳回到方法調(diào)用處,結(jié)果如下:


          此時(shí)使用list來查看,我們回到了主方法中,add方法執(zhí)行完畢,但是還未賦值給d


          使用next來執(zhí)行當(dāng)前行,并且不進(jìn)入方法調(diào)用


          此時(shí)我們執(zhí)行next,然后執(zhí)行list,會(huì)發(fā)現(xiàn)我們已經(jīng)來到了第8行,而此時(shí)如果使用step的話,我們?nèi)詴?huì)進(jìn)入add方法中,而此時(shí)我們不想再看add方法的調(diào)用了,可以使用next來直接跳過add方法,來到下一行,結(jié)果如下


          可以看到,當(dāng)我們?cè)诘?行執(zhí)行next的時(shí)候,并沒有進(jìn)入add方法內(nèi)部,而是直接將其執(zhí)行完畢來到了第9行;


          此時(shí)再使用locals命令查看變量,此時(shí)會(huì)打印出args這個(gè)main方法的入?yún)⒑蚢、b、c、d、e這5個(gè)本地變量,結(jié)果如下


          使用set命令修改e的值

          此時(shí)我們可以使用set命令來修改e的值,運(yùn)行結(jié)果如下:

          可以發(fā)現(xiàn)此時(shí)e已經(jīng)是12了


          打印當(dāng)前線程棧

          使用where all打印所有線程棧



          使用where 線程ID打印指定線程棧

          先使用threads獲取線程ID:


          然后使用where 線程ID來打印指定線程棧:


          可以看到,當(dāng)前main線程正處于Test的第9行,而這與我們實(shí)際運(yùn)行的也是一致的


          聯(lián)系我

          • 作者微信:JoeKerouac

          • 微信公眾號(hào)(文章會(huì)第一時(shí)間更新到公眾號(hào),如果搜不出來可能是改名字了,加微信即可=_=|):代碼深度研究院

          • GitHub:https://github.com/JoeKerouac


          瀏覽 77
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  国产 激情 视频 在线 | 国产亚洲视频免费观看 | 免费一区二区 | 少妇夫妻性生活的视频一级 | 97人人澡 |