JVMTI(JVM tool interface)是一套c/c++开发接口,用于对JVM进行性能分析、debug、内存管理、线程分析等各种黑科技操作
JVMTI开发1个CPU Profiler:
agent.c
JNIEXPORT jint JNICALL Agent_OnLoad(JavaVM *vm, char *options, void *reserved) {jvmtiEnv *jvmti;(*vm)->GetEnv((void **)&jvmti, JVMTI_VERSION_1_0);// ...return JNI_OK;
}
开启一个线程定时循环执行如下操作:
// 获取所有线程的jthread jvmtiError GetAllThreads(jvmtiEnv *env, jint *threads_count_ptr, jthread **threads_ptr);
// 根据jthread获取该线程信息(name、
daemon
、priority...) jvmtiError GetThreadInfo(jvmtiEnv *env, jthread thread, jvmtiThreadInfo* info_ptr);
// 根据jthread获取该线程调用栈 jvmtiError GetStackTrace(jvmtiEnv *env, jthread thread, jint start_depth, jint max_frame_count, jvmtiFrameInfo *frame_buffer, jint *count_ptr);
JVMTI开发1个Memory Profiler:
创建一个native工程,复制一份jdk中jvmti.h的头文件到项目cpp根目录(在jdk/include安装目录下)
自定义一个memory.cpp
extern "C"
JNIEXPORT jint JNICALL
Agent_OnAttach(JavaVM *vm, char *options, void *reserved) {//准备JVMTI环境,初始化mJvmtiEnvvm->GetEnv((void **) &mJvmtiEnv, JVMTI_VERSION_1_2);return JNI_OK;
}
通过jvmtiEnv->SetEventCallbacks方法设定我们想要监听的事件到jvmtiEventCallbacks集合里
jvmtiEventCallbacks callbacks;
memset(&callbacks, 0, sizeof(callbacks));
callbacks.VMObjectAlloc = &objectAlloc;
callbacks.ObjectFree = &objectFree;
//设置回调函数
mJvmtiEnv->SetEventCallbacks(&callbacks, sizeof(callbacks));
objectAlloc是监听内存申请函数,如果jvm执行内存分配事件,就会回调此函数,因此重写此函数的实现如下:
void JNICALL objectAlloc(jvmtiEnv *jvmti_env, JNIEnv *jni_env, jthread thread,jobject object, jclass object_klass, jlong size) {jvmti_env->SetTag(object, tag);tag+= 1;char *classSignature;// 获取类签名jvmti_env->GetClassSignature(object_klass, &classSignature, nullptr);// 过滤条件if(strstr(classSignature, "com/test/memory") != nullptr){__android_log_print(ANDROID_LOG_ERROR, "hello", "%s",classSignature);myVM->AttachCurrentThread( ¤tEnv, nullptr);// 这个list我们之后解释list.push_back(tag);char str[500];char *format = "%s: object alloc {Tag:%lld} \r\n";sprintf(str, format, classSignature,tag);memoryFile->write(str, sizeof(char) * strlen(str));}jvmti_env->Deallocate((unsigned char *) classSignature);
}
一个jvmti_env->SetTag的操作,这个是给这个分配的对象进行了一个打标签的动作(我们需要观察该对象是否被销毁,所以需要一个唯一标识符),我们会在释放的时候用到
objectFree是监听内存释放函数:
void JNICALL objectFree(jvmtiEnv *jvmti_env,jlong tag) {std::list<int>::iterator it = std::find(list1.begin(), list1.end(), tag);if (it != list.end()) // 找到了{__android_log_print(ANDROID_LOG_ERROR, "hello", "release %lld",tag);char str[500];char *format = "release tag %lld\r\n";//ALOGI(format, GetCurrentSystemTime().c_str(),threadInfo.name, classSignature, size, tag);sprintf(str, format,tag);memoryFile->write(str, sizeof(char) * strlen(str));}
}
记录内存分配信息:memoryFile->write(str, sizeof
(
char
) * strlen(str))
void MemoryFile::write(char *data, int dataLen) {mtx.lock();if(currentSize + dataLen >= m_size){resize(currentSize+dataLen);}memcpy(ptr + currentSize, data, dataLen);currentSize += dataLen;mtx.unlock();
}
通过SetEventNotificationMode函数开启真正监听/关闭监听
//开启监听
mJvmtiEnv->SetEventNotificationMode(JVMTI_ENABLE, JVMTI_EVENT_VM_OBJECT_ALLOC, nullptr);
mJvmtiEnv->SetEventNotificationMode(JVMTI_ENABLE, JVMTI_EVENT_OBJECT_FREE, nullptr);jvmtiError SetEventNotificationMode(jvmtiEventMode mode,jvmtiEvent event_type,jthread event_thread,...) {return functions->SetEventNotificationMode(this, mode, event_type, event_thread);
}