原文
一些IDE提供“方法斷點”的功能,可以讓斷點除錯看起來非常簡潔,然而在除錯程序中我們會發現除錯反應時間很長,除錯器的性能大大降低,在本文中,我會簡單解釋方法斷點的實作原理,以及為何導致性能變差的原因,
為了更好的理解,我先簡單說明一下斷點是如何實作的,以及除錯器的作業原理,
JPDA(Java Platform Debugger Architecture)
JPDA是JAVA除錯框架,主要用于debugger(除錯器)和debuggee(除錯程式或行程)之間的通信,JPDA主要由三個主要API構成,
- JVM TI(JVM Tool Interface) : 一個native介面,定義了VM提供debug的函式,
- Java Debug Wire Protocol(JDWP):JDWP是一個定義debugger和debuggee通信的Api,
- Java Debug Interface(JDI): Java介面,用于前端和后端的通信互動,JDI內部實作了JDWP介面,
- 下圖和文章中的前后端(back-end and font-end)分別指的是運行在VM上的除錯程式(行程)和編輯器,

- 除錯鏈:相關事件發生時(比如打斷點,單步除錯,除錯時修改引數值),VM通過回呼(JNI: java Native Interface,VM通過JNI來呼叫Native Interface)呼叫JVM TI,然后back-end發送event給font-end,debugger通過JDI和JDWP與后端通信,
為何要用方法斷點
如果呼叫的方法無法訪問原始碼,或者方法內有多個if出口,此時用方法斷點很簡潔,
JAVA斷點原理
在編輯器打一個斷點,往往內部會進行三步
- 允許斷點事件:VM允許debugger激活各種事件,font-end呼叫
SetEventNotificationMode()方法啟用can_generate_breakpoint_events,當運行到斷點處,VM會觸發事件通過debugger鏈回傳值, - 注冊斷點:通過
SetBreakpoint方法設定斷點,當執行緒運行到斷點處,VM會將所有active執行緒暫停,并且觸發斷點事件,SetBreakpoint(jvmtiEnv* env, jmethodID method, //注意一下此變數,下文會再次提到, jlocation location) - 斷點事件:VM觸發的事件叫斷點事件,用于通知debugger,事件:
Breakpoint(xxx)
方法斷點
實際上JDPA不提供方法斷點的功能,方法斷點是編輯器提供的,
debugger呼叫上文說的 SetEventNotificationMode(),
啟用 can_generate_method_entry_events 和 can_generate_method_exit_events,當VM運行進入和退出方法時,會向debugger發送 方法進入退出事件:
MethodEntry(....,JmethodID method)
MethodExit(....,JmethodID method)
斷點實作流程:
- IDE將斷點添加到編輯器內置維護的一個斷點list里,
- debugger呼叫上文說的SetEventNotificationMode(),啟用entry events和exit events,當VM運行代碼進入和退出方法時,會向debugger發送事件,
- 每當進入和退出方法時,VM會向font-end發送MethodEntry或MethodExit,
- IDE根據事件中的jmethodID,來檢索該id是否存在于斷點list中,
- 如果存在,debugger則呼叫
SetBreakPoint方法,將請求發送到VM, - VM運行代碼到斷點處,停止活動執行緒,并且將event回傳debugger
和普通斷點的區別在于:方法斷點在流程中需要先判斷該方法是否被前端標記為應該要打上斷點,然后才是注冊斷點,
除錯方法斷點為何很慢
- JmethodID:JmethodID是正在運行方法的識別符號,每次VM需要回傳MethodEntry和MethodExit時都需要攜帶JmethodID,然而VM查找獲取JmethodID需要較長時間,
- communication:methodEntry和MethodExit導致前端和后端之間進行大量的通信往返,
- VM callback is synchronization:VM觸發事件使用回呼時,經過以下幾個步驟(都是同步操作):
- 將context切換到back-end,back-end通知font-end
- font-end根據回傳的jmethodID,查找是否存在于斷點list中,
在此期間代碼執行是暫停的,
總結
- 盡量減少方法斷點的使用,
- 如果不必要,可以只使用methodEntry,不激活methodExit,減少查找以及通信次數,
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/518818.html
標籤:Java
