色哟哟视频在线观看-色哟哟视频在线-色哟哟欧美15最新在线-色哟哟免费在线观看-国产l精品国产亚洲区在线观看-国产l精品国产亚洲区久久

0
  • 聊天消息
  • 系統(tǒng)消息
  • 評(píng)論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會(huì)員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識(shí)你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

詳解Java DEBUG的基本原理

OSC開源社區(qū) ? 來源:OSCHINA 社區(qū) ? 2024-01-05 10:10 ? 次閱讀

作者:京東云開發(fā)者-京東保險(xiǎn)蔣信

Debug 的時(shí)候,都遇到過手速太快,直接跳過了自己想調(diào)試的方法、代碼的時(shí)候吧……

一旦跳過,可能就得重新執(zhí)行一遍,準(zhǔn)備數(shù)據(jù)、重新啟動(dòng)可能幾分鐘就過去了。

好在 IDE 們都很強(qiáng)大,還給你后悔的機(jī)會(huì),可以直接刪除某個(gè) Stack Frame,直接返回到之前的狀態(tài),確切的說是返回到之前的某個(gè) Stack Frame,從而實(shí)現(xiàn)讓程序 “逆向運(yùn)行”。

0f2838ac-aaf3-11ee-8b88-92fbcf53809c.png

這個(gè) Reset Frame 的能力,可不只是返回上一步,上 N 步也是可以的;選中你期望的那個(gè)幀,直接 Reset Frame/Drop Frame,可以直接回到調(diào)用棧上的某個(gè)棧幀,時(shí)間反轉(zhuǎn)!

可惜這玩意也不是那么萬能,畢竟是通過 stack pop 這種操作實(shí)現(xiàn),實(shí)際上只是給調(diào)用棧棧頂?shù)?N 個(gè) frame pop 出來而已,還談不上是真正的 “反向 DEBUG”。

相比之下, GDB 的 Reverse Debugging 就比較強(qiáng)大,真正的 “反向” DEBUG,逆向運(yùn)行,實(shí)現(xiàn)回放。

所以吧在運(yùn)行過程中,已經(jīng)修改的數(shù)據(jù),比如引用傳遞的方法參數(shù)、變量,一旦修改肯定回退不了,不然真的成時(shí)光機(jī)了。

這些亂七八糟的調(diào)試功能,都是基于 Java 內(nèi)置的 Debug 體系來實(shí)現(xiàn)的。

JAVA DEBUG 體系

Java 提供了一個(gè)完整的 Debug 體系JPDA(Java Platform Debugger Architecture),這個(gè) JPDA 架構(gòu)體系由 3 部分組成:

JVM TI- Java VM Tool Interface

JDWP- Java Debug Wire Protocol

JDI- Java Debug Interface

如果結(jié)合 IDE 來看,那么一個(gè)完整的 Debug 功能看起來就是這個(gè)樣子:

0f3974e6-aaf3-11ee-8b88-92fbcf53809c.png

解釋一下這個(gè)體系:

JVM TI 是一個(gè) JVM 提供的一個(gè)調(diào)試接口,提供了一系列控制 JVM 行為的功能,比如分析、調(diào)試、監(jiān)控、線程分析等等。也就是說,這個(gè)接口定義了一系列調(diào)試分析功能,而 JVM 實(shí)現(xiàn)了這個(gè)接口,從而提供調(diào)試能力。

不過吧,這個(gè)接口畢竟是 C++ 的,調(diào)用起來確實(shí)不方便,所以 Java 還提供了 JDI 這么個(gè) Java 接口。

JDI 接口使用 JDWP 這個(gè)私有的應(yīng)用層協(xié)議,通過 TCP 和目標(biāo) VM 的 JVMTI 接口進(jìn)行交互。

也可以把簡(jiǎn)單這個(gè) JDWP 協(xié)議理解為 JSF/Dubbo 協(xié)議;相當(dāng)于 IDE 里通過 JDI 這個(gè) SDK,使用 JDWP 協(xié)議調(diào)用遠(yuǎn)程 JVMTI 的 RPC 接口,來傳輸調(diào)試時(shí)的各種斷點(diǎn)、查看操作。

可能有人會(huì)問,搞什么套殼!要什么 JDWP,我直接 JVMTI 調(diào)試不是更香,鏈路越短性能越高!

當(dāng)然可以,比如 Arthas 里的部分功能,就直接使用了 JVMTI 接口,要什么 JDI!直接 JVMTI 干就完了。

開個(gè)玩笑,Arthas 畢竟不是 Debug 工具,人家根本就不用 JDI 接口。而且 JVMTI 的能力也不只是斷點(diǎn),它的功能非常多:

0f4dccde-aaf3-11ee-8b88-92fbcf53809c.png

左邊的功能類,提供了各種亂七八糟的功能,比如我們常用的添加一個(gè)斷點(diǎn):

jvmtiError
SetBreakpoint(jvmtiEnv* env,
            jmethodID method,
            jlocation location)

右邊的事件類,可以簡(jiǎn)單的理解為回調(diào);還是拿斷點(diǎn)舉例,如果我用上面的 SetBreakpoint 添加了一個(gè)斷點(diǎn),那么當(dāng)執(zhí)行到該位置時(shí),就會(huì)觸發(fā)這個(gè)事件:

void JNICALL
Breakpoint(jvmtiEnv *jvmti_env,
            JNIEnv* jni_env,
            jthread thread,
            jmethodID method,
            jlocation location)

JVMTI 的功能非常之多,而 JDI 只是實(shí)現(xiàn)了部分 JVMTI 的方法,所以某些專業(yè)的 Profiler 工具,可能會(huì)直接使用 JVMTI,從而實(shí)現(xiàn)更豐富的診斷分析功能。

遠(yuǎn)程調(diào)試與本地調(diào)試

不知道大家有沒有留意過本地 Debug 啟動(dòng)時(shí)的日志: 0f6ad478-aaf3-11ee-8b88-92fbcf53809c.png 第一行是隱藏了后半段的啟動(dòng)命令,展開后是這個(gè)樣子:

/path/to/java -agentlib:jdwp=transport=dt_socket,address=127.0.0.1:53631,suspend=y,server=n -javaagent:/path/to/jetbrains/debugger-agent.jar ...

第二行是一個(gè) Connected 日志,意思是使用 socket 連接到遠(yuǎn)程 VM 的 53631 端口 上一段說到,IDE 通過 JDI 接口,使用 JDWP 協(xié)議和目標(biāo) VM 的 JVMTI 交互。這里的 53631 端口,就是目標(biāo) JVM 暴露出的 JVM TI 的 server 端口。 而第一行里,IDEA 自動(dòng)給我們加上了-agentlib:jdwp=transport=dt_socket,address=127.0.0.1:53631這么一段,這個(gè)參數(shù)的意思就是,讓 jvm 以 53631 暴露 jdwp 協(xié)議 小知識(shí),這個(gè) agentlib 可不只是為 jvmti 提供的。它還可以讓 JVM 加載其他的 native lib 包,直接 “外掛” 到你的 jvm 上,下面是 “外掛” 的參數(shù)格式: 0f7b44d4-aaf3-11ee-8b88-92fbcf53809c.png 所以吧,上面的描述其實(shí)不太嚴(yán)謹(jǐn),更專業(yè)的說法是: 讓 JVM 加載 JDWP 這個(gè) agent 庫(kù),參數(shù)為?transport=dt_socket,address=127.0.0.1:53631,這個(gè) jdwp agent 庫(kù)以 53631 端口提供了 jdwp 協(xié)議的 server。只不過這個(gè) jdwp 是 jvm 內(nèi)部的庫(kù),不需要額外的 so/dylib/dll 文件。 如有需要,你完全可以弄個(gè) “datupiao” 的 agentlib,“外掛” 到這個(gè) jvm 上,然后在這個(gè) lib 里調(diào)用 JVMTI 接口,然后暴露個(gè)端口提供服務(wù)和遠(yuǎn)程交互,實(shí)現(xiàn)自己的 jdwp! 可能某些老板們注意到了,本地調(diào)試還要 127.0.0.1 走 tcp 交互一遍,那遠(yuǎn)程調(diào)試呢? 基于上面的解釋,本地調(diào)試和遠(yuǎn)程調(diào)試真的沒啥區(qū)別!或者說,在目前 IDEA/Eclipse 的實(shí)現(xiàn)下,不存在本地調(diào)試,都是遠(yuǎn)程!只不過一個(gè)是 127.0.0.1,一個(gè)是遠(yuǎn)程的 IP 而已。 在本地調(diào)試時(shí),IDEA 會(huì)自動(dòng)給我們的 JVM 增加?agent?參數(shù),隨機(jī)指定一個(gè)端口,然后通過 JDI 接口連接,代碼大概長(zhǎng)這樣(JDI 的 SDK 在 JDK_HOME/lib/tools.jar ):
Map env = connector.defaultArguments();
env.get("hostname").setValue(hostname);
env.get("port").setValue(port);

VirtualMachine vm = connector.attach(env);

瞅瞅, VirtualMachine 里的就這點(diǎn)方法,能力上比 JVMTI 還是差遠(yuǎn)了

List classesByName(String className);

List allClasses();

void redefineClasses(Map classToBytes);

List allThreads();

void suspend();

void resume();

List topLevelThreadGroups();

EventQueue eventQueue();

EventRequestManager eventRequestManager();

VoidValue mirrorOfVoid();

Process process();

再回來看看 IDEA 中獨(dú)立的遠(yuǎn)程調(diào)試,配置好之后,紅框里的信息會(huì)提示你 ,遠(yuǎn)程的 JVM 需增加這一段啟動(dòng)參數(shù),而且支持多個(gè)版本 JDK 的格式,CV 大法就能直接用。 0f89c392-aaf3-11ee-8b88-92fbcf53809c.png

-agentlib 和 -javaagent

有些細(xì)心的同學(xué)可能發(fā)現(xiàn)了,IDEA 默認(rèn)的啟動(dòng)腳本里,同時(shí)配置了 -agentlib 和 -javaagent。

-javaagent:/path/to/jetbrains/debugger-agent.jar

這個(gè) debugger-agent 吧,其實(shí)也沒干啥事,只是對(duì) JDK 內(nèi)置的一些線程做了些增強(qiáng),輔助 IDEA 的 debug 功能,支持一些異步的調(diào)試。 0fa1aeee-aaf3-11ee-8b88-92fbcf53809c.png agentlib、javaagent 這倆兄弟,定位其實(shí)很像,都是加載自定義的代碼。 不過區(qū)別在于,agentlib 是加載 native lib,需要 c/cpp 去寫,相當(dāng)于外掛自己的代碼在 jvm 上,可以為所欲為,比如在 agentlib 里調(diào)用上面說的 JVMTI 。 而 javaagent 是用 java 寫的,可以直接用上層的 Instrumentation API,做一些類的增強(qiáng)轉(zhuǎn)換之類,這也是大多數(shù) APM Agent、Profiler Agent 實(shí)現(xiàn)的基本原理。

Arthas 的玩法

Arthas 的核心入口,其實(shí)還是 javaagent,支持靜態(tài)加載和動(dòng)態(tài)加載兩種玩法。 靜態(tài)沒啥好說的,啟動(dòng)腳本里增加一個(gè)-javaagent:/tmp/test/arthas-agent.jar,然后為所欲為。 動(dòng)態(tài)的叫 attach,使用 Java 提供的VirtualMachine就可以實(shí)現(xiàn)運(yùn)行時(shí)添加 -javaagent,效果一樣:

VirtualMachine virtualMachine = VirtualMachine.attach(virtualMachineDescriptor);
virtualMachine.loadAgent(agentPath, agentArgs);

這個(gè) Agent 在 JVM 里啟動(dòng)了一個(gè) TCP server,用于收發(fā) Arthas Client 的各種 trace、watch 、Dashboard 等指令,然后通過 Instrumentation 增強(qiáng) Class 插入代碼、或者直接調(diào)用某些 Java API,實(shí)現(xiàn)各種功能。 注意到了嗎?Arthas 可以直接下載一個(gè) jar 包,java -jar 就能連上。 其實(shí)吧,它這個(gè)直接啟動(dòng)的 jar 包,是一個(gè) boot 包,啟動(dòng)之后把亂七八糟的 jar 都下載下來。接著動(dòng)態(tài) attach 的方式,連接到本機(jī)指定進(jìn)程號(hào)的 JVM,然后再為所欲為。 在 3.5 版本之后,Arthas 還新增了一個(gè)vmtool命令,這個(gè)命令可以直接獲取內(nèi)存中的指定對(duì)象實(shí)例。
$ vmtool --action getInstances --className java.lang.String --limit 10
@String[][
    @String[com/taobao/arthas/core/shell/session/Session],
    @String[com.taobao.arthas.core.shell.session.Session],
    @String[com/taobao/arthas/core/shell/session/Session],
    @String[com/taobao/arthas/core/shell/session/Session],
    @String[com/taobao/arthas/core/shell/session/Session.class],
    @String[com/taobao/arthas/core/shell/session/Session.class],
    @String[com/taobao/arthas/core/shell/session/Session.class],
    @String[com/],
    @String[java/util/concurrent/ConcurrentHashMap$ValueIterator],
    @String[java/util/concurrent/locks/LockSupport],
]

直接獲取內(nèi)存對(duì)象,這玩意只靠 Instrumentation API 可做不到。Arthas 搞了個(gè)騷操作,直接 JNI 調(diào)用自定義 lib,用過 cpp 直接調(diào)用了 JVMTI 的 API,融合了 Instrumentation 和 JVMTI 的能力,這下是真的為所欲為了!
#include 
#include 
#include 
#include 
#include "arthas_VmTool.h" // under target/native/javah/

static jvmtiEnv *jvmti;

...

extern "C"
JNIEXPORT jobjectArray JNICALL
Java_arthas_VmTool_getInstances0(JNIEnv *env, jclass thisClass, jclass klass, jint limit) {
    jlong tag = getTag();
    limitCounter.init(limit);
    jvmtiError error = jvmti->IterateOverInstancesOfClass(klass, JVMTI_HEAP_OBJECT_EITHER,
                                               HeapObjectCallback, &tag);
    if (error) {
        printf("ERROR: JVMTI IterateOverInstancesOfClass failed!%u
", error);
        return NULL;
    }

    jint count = 0;
    jobject *instances;
    error = jvmti->GetObjectsWithTags(1, &tag, &count, &instances, NULL);
    if (error) {
        printf("ERROR: JVMTI GetObjectsWithTags failed!%u
", error);
        return NULL;
    }

    jobjectArray array = env->NewObjectArray(count, klass, NULL);
    //添加元素到數(shù)組
    for (int i = 0; i < count; i++) {
        env->SetObjectArrayElement(array, i, instances[i]);
    }
    jvmti->Deallocate(reinterpret_cast(instances));
    return array;
}

總結(jié)

Debug 基于 JDPA 體系

IDE 直接接入 JDPA 體系中的 JDI 接口完成

JDI 通過 JDWP 協(xié)議,調(diào)用遠(yuǎn)程 VM 的 JVMTI 接口

JDWP 是通過 agentlib 加載的,agentlib 算是一個(gè) native 的靜態(tài) “外掛” 接口

javaagent 是 JAVA 層面的 “外掛” 接口,用過 Instrumentation API(Java)實(shí)現(xiàn)各種功能,主要用于 APM、Profiler 工具

如果你想,在 javaagent 里調(diào)用功能更豐富的 JVMTI 也不是不行。

審核編輯:湯梓紅

聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場(chǎng)。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請(qǐng)聯(lián)系本站處理。 舉報(bào)投訴
  • JAVA
    +關(guān)注

    關(guān)注

    19

    文章

    2966

    瀏覽量

    104702
  • 程序
    +關(guān)注

    關(guān)注

    117

    文章

    3785

    瀏覽量

    81004
  • 代碼
    +關(guān)注

    關(guān)注

    30

    文章

    4779

    瀏覽量

    68522
  • DEBUG
    +關(guān)注

    關(guān)注

    3

    文章

    93

    瀏覽量

    19907

原文標(biāo)題:反向Debug了解一下?揭秘Java DEBUG的基本原理

文章出處:【微信號(hào):OSC開源社區(qū),微信公眾號(hào):OSC開源社區(qū)】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。

收藏 人收藏

    評(píng)論

    相關(guān)推薦

    步進(jìn)電機(jī)基本原理

    本帖最后由 eehome 于 2013-1-5 09:48 編輯 步進(jìn)電機(jī)基本原理
    發(fā)表于 08-16 16:17

    擴(kuò)頻通信的基本原理

    附件非常詳解的介紹了擴(kuò)頻通信的基本原理,本人做通信快3年了,是我見過的介紹擴(kuò)頻通信最好的資料,分享一下!
    發(fā)表于 11-15 10:57

    串聯(lián)諧振逆變器的基本原理

    串聯(lián)諧振通常伴有逆變器。該組合稱為串聯(lián)諧振逆變器。什么是基本原理?讓我簡(jiǎn)要介紹串聯(lián)諧振逆變器的一些基本原理。]首先給你看一張圖片:
    發(fā)表于 11-07 10:21

    IC測(cè)試基本原理是什么?

    IC測(cè)試基本原理是什么?ATE測(cè)試向量是什么?
    發(fā)表于 05-07 06:43

    IC測(cè)試的基本原理是什么?

    本文詳細(xì)介紹了芯片開發(fā)和生產(chǎn)過程中的IC測(cè)試基本原理
    發(fā)表于 05-08 07:33

    TSP控制的基本原理是什么?

    TSP控制的基本原理是什么?
    發(fā)表于 05-11 06:39

    電機(jī)轉(zhuǎn)動(dòng)的基本原理是什么?

    電機(jī)轉(zhuǎn)動(dòng)的基本原理是什么?電機(jī)運(yùn)動(dòng)的基本原則有哪些?
    發(fā)表于 07-21 07:59

    線性電源的基本原理是什么

    多路線性電源 AC-DC穩(wěn)壓電源 低紋波電源 可調(diào)線性電源 原理圖PCB目錄多路線性電源 AC-DC穩(wěn)壓電源 低紋波電源 可調(diào)線性電源 原理圖PCB基本原理芯片選型原理圖&3D-PCB具體
    發(fā)表于 07-30 07:47

    無線充電的基本原理是什么

    一 、無線充電基本原理無線充電的基本原理就是我們平時(shí)常用的開關(guān)電源原理,區(qū)別在于沒有磁介質(zhì)耦合,那么我們需要利用磁共振的方式提高耦合效率,具體方法是在發(fā)送端和接收端線圈串并聯(lián)電容,是發(fā)送線圈處理諧振
    發(fā)表于 09-15 06:01

    RAID技術(shù)的基本原理是什么

    RAID技術(shù)的基本原理是什么?RAID技術(shù)有哪幾個(gè)優(yōu)勢(shì)?
    發(fā)表于 10-14 12:01

    IIC的基本原理是什么?

    IIC的基本原理是什么?
    發(fā)表于 11-25 08:46

    串口通信基本原理是什么?

    串口通信基本原理是什么?串行通信的分類有哪些?
    發(fā)表于 12-03 06:08

    串口通信的基本原理是什么?

    同步通信和異步通信的區(qū)別是什么?串口通信的基本原理是什么?
    發(fā)表于 12-13 06:46

    步進(jìn)馬達(dá)基本原理

    步進(jìn)馬達(dá)基本原理步進(jìn)馬達(dá)基本原理步進(jìn)馬達(dá)基本原理
    發(fā)表于 11-30 11:55 ?8次下載

    一文詳解PIN二極管基本原理及設(shè)計(jì)

    【半導(dǎo)光電】PIN二極管基本原理及設(shè)計(jì)詳解
    發(fā)表于 01-02 07:25 ?1394次閱讀
    主站蜘蛛池模板: 啊轻点啊再深点视频免费| 色www.亚洲免费视频| 2021国产精品视频一区| 捆绑调教网站| 91国在线产| 欧美精品v欧洲高清| JAVASCRIPTJAVA水多多| 青青草狠狠干| 哒哒哒高清视频在线观看| 日韩视频中文字幕精品偷拍| 观看免费做视频| 无人影院在线播放| 国产午夜精品鲁丝片| 亚洲日本一区二区三区在线不卡 | 亚洲精品成人A8198A片漫画| 国产亚洲高清视频| 亚洲视频在线观看地址| 久久婷婷电影网| 99re久久热免费视频| 欧美日韩另类在线专区| 动漫美女禁区图| 午夜福利体验免费体验区| 国产中的精品AV一区二区| 杨幂视频在线观看1分30秒| 久久免费精品国产72精品剧情| 1819sextub欧美中国| 全肉高H短篇合集| 国产精品AV无码免费播放| 亚洲精品国产国语| 久久久视频2019午夜福利| 99久女女精品视频在线观看| 日韩欧美视频一区二区| 国产精品野外AV久久久| 亚洲中文字幕在线第六区| 麻豆人妻换人妻X99| 波多结衣一区二区三区| 无码任你躁久久久久久老妇双奶| 激情综合色| 99久久婷婷国产综合精品青草 | 最新高清无码专区| 秋霞午夜鲁丝片午夜精品久|