简介
在介绍instrument是什么之前,先来看几个定义:
JVMTI(JVM tool interface):它是JVM提供的一系列native编程接口。
Agent:与JVM进行通信的外部进程,它们通过调用JVMTI进行交互,可进行的操作包括设置JVM回调函数、获取当前虚拟机状态信息等
Instrument:Jdk提供的"java.lang.instrument"包,与JVM进行交互,可以看作为一个Instrument Agent。
https://www.ibm.com/developerworks/cn/java/j-lo-jpda2/index.html?ca=drs-
整体流程
接上文,当JVM接收到execute(“load”,“instrument”,“false”,options)命令之后,开始进行动态链接库的加载。
- "load"命令——对应load_agent方法:
- 接收参数:op->arg(0)、 op->arg(1)、op->arg(2);(“instrument”、是否绝对路径、agentpath=args)
- 判断 if(arg(0)==“instrument”)先加载"java.instrument"模块,再load_agent_library
- load_agent_library:
- 首先加载动态库:“libinstrument.so”,加载instrument Agent(JVM定义Linux系统中,加载的动态链接库名字是"lib"+args(0)+".so")
- 调用库中的Agent_OnAttach方法。
从Agent_OnAttach开始,是libinstrument.so中的内容:
关于libInstrument.so库,我认为可以当做是一个底层Agent。
它直接调用了JVMTI提供的回调方法,然后加载我们自定义的agent,避免了我们自己的agent与JVMTI直接通信。
源码分析
// Implementation of "load" command.
static jint load_agent(AttachOperation* op, outputStream* out) {
// get agent name and options
const char* agent = op->arg(0);
const char* absParam = op->arg(1);
const char* options = op->arg(2);
// If loading a java agent then need to ensure that the java.instrument module is loaded
if (strcmp(agent, "instrument") == 0) {
Thread* THREAD = Thread::current();
ResourceMark rm(THREAD);
HandleMark hm(THREAD);
JavaValue result(T_OBJECT);
Handle h_module_name = java_lang_String::create_from_str("java.instrument", THREAD);
JavaCalls::call_static(&result,
SystemDictionary::module_Modules_klass(),
vmSymbols::loadModule_name(),
vmSymbols::loadModule_signature(),
h_module_name,
THREAD);
if (HAS_PENDING_EXCEPTION) {
java_lang_Throwable::print(PENDING_EXCEPTION, out);
CLEAR_PENDING_EXCEPTION;
return JNI_ERR;
}
}
return JvmtiExport::load_agent_library(agent, absParam, options, out);
}
接收到的三个参数对应我们发送命令时的三个:“instrument”、是否绝对路径、agentpath=args;
先加载java.instrument模块,再加载Agent,调用JvmtiExport::load_agent_library(agent, absParam, options, out),当成功时返回码为0.
jint JvmtiExport::load_agent_library(const char *agent, const char *absParam,
const char *options, outputStream* st) {
char ebuf[1024];
char buffer[JVM_MAXPATHLEN];
void* library = NULL;
jint result = JNI_ERR;
const char *on_attach_symbols[] = AGENT_ONATTACH_SYMBOLS;
size_t num_symbol_entries = ARRAY_SIZE(on_attach_symbols);
// The abs paramter should be "true" or "false"
bool is_absolute_path = (absParam != NULL) && (strcmp(absParam,"true")==0);
// Initially marked as invalid. It will be set to valid if we can find the agent
AgentLibrary *agent_lib = new AgentLibrary(agent, options, is_absolute_path, NULL);
// Check for statically linked in agent. If not found then if the path is
// absolute we attempt to load the library. Otherwise we try to load it
// from the standard dll directory.
if (!os::find_builtin_agent(agent_lib, on_attach_symbols, num_symbol_entries)) {
if (is_absolute_path) {
library = os::dll_load(agent, ebuf, sizeof ebuf);
} else {
// Try to load the agent from the standard dll directory
if (os::dll_locate_lib(buffer, sizeof(buffer), Arguments::get_dll_dir(),
agent)) {
library = os::dll_load(buffer, ebuf, sizeof ebuf);
}
if (library == NULL)