做爲java碼農確定碰到過當咱們debug到一些class的時候,發現當進入到某個方法裏是看不到聲明的入參名,取而代之的是arg0,arg1等,繼續深刻更是看不到局部變量,這主要是java類編譯的時候沒有加-g參數致使的,而爲何咱們本身在eclipse中寫的代碼倒是能夠正常跟蹤呢,緣由很簡單,由於eclipse自行編譯的時候是帶-g參數編譯的。java
這種問題在咱們安裝的jdk中更爲常見,爲了節省生成的jar空間,因而javac編譯都是不帶-g參數的,好比rt.jar,裏面的類都是不能被正常debug的,由於生成的class信息中沒有輔助debug的信息,好比行號,局部變量信息等,那是否是咱們經過手動編譯jdk便可徹底debug jdk中的任意java類呢,答案是否認的。linux
說到debug,那就要先了解下jdpa體系,jdpa包含三部分,從低到高是jvmti->jdwp->jdi,jvmti是一套本地代碼接口,jvm暴露出來的擴展接口,全部的調試功能都是經過其提供出來的,不少jvm性能工具都是基於這些接口來實現的;jdwp是java調試線協議,其主要規範了jvmti和jdi之間的通訊協議,好比命令的格式是什麼,回覆的格式是什麼等,固然還包括不少類型的定義,理論上其不包括通訊層的實現,通訊層的實現能夠是socket,也能夠是共享內存等;jdi位於最上層,定義了調試器所須要的調試接口,基於這些接口調試器能夠方便地瞭解目標虛擬機的狀態信息,你們最熟悉的有eclipse IDE。eclipse
那java debug的原理是什麼呢,說簡單點主要是經過實現jdwp的動態連接庫,利用agentlib的機制(其實就是jvmti的擴展機制)在啓動或者運行器動態執行動態連接庫,-agentlib:jdwp=transport=dt_socket,suspend=y,address=localhost:58140 ,相似如上的啓動配置,jdwp是動態連接庫的名稱,會根據所在的平臺自動查找對應的動態庫,好比linux下會找到jdwp.so,mac下會找到jdwp.dylib等,至於這個agent怎麼實現的就很少說了。jvm
那回過來講說爲何說不能debug到rt.jar中的每行代碼呢,該agent往jvmti環境中註冊了一個回調方法,回調方法裏幹了啥呢,好比建立serversocket來等待鏈接,這主要在咱們設置了調試端口,而且suspend=y的狀況,該回調方法是在vm初始化完畢以後纔去執行的,而在vm初始化的過程當中經過啓動類加載器已經加載了不少類了,執行了很多java邏輯,因此這些邏輯是根本跟蹤不到的,好比sun.misc.Launcher的建立等。socket