JVMTI 笔记

server/2025/1/1 14:35:43/

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( &currentEnv, 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);
}

参考:Android性能优化之JVMTI与内存分配_Android_脚本之家


http://www.ppmy.cn/server/154283.html

相关文章

探索 .idea 文件夹:Java Maven 工程的隐形守护者

一、.idea文件夹深度解析&#xff1a;IntelliJ IDEA项目配置的核心 在Java Maven工程的开发环境中&#xff0c;.idea文件夹扮演着举足轻重的角色。这是IntelliJ IDEA项目特有的一个配置文件夹&#xff0c;它包含了项目所需的各种配置信息&#xff0c;以确保项目能够在不同的开…

【JavaEE进阶】Spring传递请求参数

目录 &#x1f38d;序言 &#x1f334;传递单个参数 &#x1f340;传递多个参数 &#x1f384;传递对象 &#x1f333;后端参数重命名&#xff08;后端参数映射&#xff09; &#x1f6a9;ReuqestParam注解 &#x1f38d;序言 访问不同的路径,就是发送不同的请求.在发送…

如何在 Ubuntu 22.04 上安装 Elasticsearch

简介 在本教程中&#xff0c;你将学习如何在 Ubuntu 22.04 服务器上安装 Elasticsearch。此外&#xff0c;你还将学习如何使用 Elasticsearch REST API 索引和操作数据。 Elasticsearch 是一个基于 Apache Lucene Library 的免费分布式搜索和分析引擎。它是一个快速且可扩展的…

【落羽的落羽 C语言篇】自定义类型——联合体、枚举

文章目录 一、联合体1. 联合体类型的声明2. 联合体的特点3. 联合体的大小4. 联合体和结构体的对比 二、枚举1. 枚举类型的声明2. 枚举类型的优点 一、联合体 1. 联合体类型的声明 联合体像结构体一样&#xff0c;也是由一个或多个成员构成&#xff0c;这些成员可以是不同的类…

【大模型】wiki中文语料的word2vec模型构建

在自然语言处理&#xff08;NLP&#xff09;任务中&#xff0c;词向量&#xff08;Word Embedding&#xff09;是一个非常重要的概念。通过将词语映射到一个高维空间中&#xff0c;我们能够以向量的形式表达出词语之间的语义关系。Word2Vec作为一种流行的词向量学习方法&#x…

SPI接口

一、SPI总线 SPI接口是Motorola 首先提出的全双工三线/四线同步串行外围接口采用主从模式&#xff08;Master Slave&#xff09;架构。 时钟由Master控制&#xff0c;在时钟移位脉冲下&#xff0c;数据按位传输&#xff0c;高位在前&#xff0c;低位在后&#xff08;MSB firs…

如何在centos系统上挂载U盘

在CentOS上挂载NTFS格式的U盘,需要执行一系列步骤,包括识别U盘设备、安装必要的软件、创建挂载点,并最终挂载U盘。以下是在CentOS上挂载NTFS格式U盘的详细步骤: 一、准备工作 确认CentOS版本: 确保你的CentOS系统已经安装并正常运行。不同版本的CentOS在命令和工具方面可能…

iDP3复现代码数据预处理全流程(二)——vis_dataset.py

vis_dataset.py 主要作用在于点云数据的可视化&#xff0c;并可以做一些简单的预处理 关键参数基本都在 vis_dataset.sh 中定义了&#xff0c;需要改动的仅以下两点&#xff1a; 1. 点云图像保存位置&#xff0c;因为 dataset_path 被设置为了绝对路径&#xff0c;因此需要相…