JVMTI 中间JNI系列功能,线程安全和故障排除技巧

jni functions

在使用 JVMTI 的过程中,有一大系列的函数是在 JVMTI 的文档

没有提及的,但在实际使用却是很实用的。

这就是 jni functions.

比如。在使用 SingleStep 函数时。

void JNICALL
SingleStep(jvmtiEnv *jvmti_env,
JNIEnv* jni_env,
jthread thread,
jmethodID method,
jlocation location)

我们就能够使用 jni_env 来调用 jni functions 中的一系列函数。

比如:

jclass mainClass = (*jni_env)->FindClass(jni_env, "Foo");
jfieldID fieldID = (*jni_env)->GetStaticFieldID(jni_env, mainClass, "x", "I");
jint fieldValue = (*jni_env)->GetStaticIntField(jni_env, mainClass, fieldID);

通过使用 jni functions 就能够获取 Foo 类中的静态整型变量的值。

另外在 jni functions 文档 中还有大量易用的

函数,都是在 JVMTI 文档中没有提及的。很实用。

事件回调函数的线程安全

在 JVMTI 中有一系列回调函数,当使用 SetEventNotificationModeSetEventCallbacks 设置了某个事件的回调函数后。Java 虚拟机

在对应事件发生时,就会调用我们在 JVMTI 的 agent 中写的回调函数。

千万注意:多数回调函数须要保证线程安全

也就是说,我们写的回调函数要保证是可重入的。不然的话,一个线程运行时进入了回调函数,还没运行完这个回调函数时,可能会被切换

到还有一线程,而还有一线程也可能又一次进入这个回调函数,运行完之后,又切换回前一线程时,才继续运行上一个没有运行完的回调函数。

假设

你使用了全局变量,就要格外注意上述情况可能导致的数据不一致问题。

解决问题的最简单的办法就是使用 Raw Monitor。

在 Agent_OnLoad 函数中创建一个 Raw Monitor:

(*jvmti)->CreateRawMonitor(jvmti, "singelStep", &singleStepMonitorId);

然后。在回调函数的開始和结束时,使用这个 Raw Monitor 形成一个临界区,使得多个线程不能同一时候进入这个临界区:

void JNICALL
callbackSingleStep(
jvmtiEnv *jvmti,
JNIEnv* jni,
jthread thread,
jmethodID method,
jlocation location) { (*jvmti)->RawMonitorEnter(jvmti, singleStepMonitorId); ... (*jvmti)->RawMonitorExit(jvmti, singleStepMonitorId);
}

JVMTI agent 的调试

JVMTI 的 agent 假设出错,Java 虚拟机就会直接崩溃,同一时候生成一个 log,我们须要依据这个 log 推測 agent 中哪里出现了错误,比如:

#
# A fatal error has been detected by the Java Runtime Environment:
#
# EXCEPTION_ACCESS_VIOLATION (0xc0000005) at pc=0x000000006f99f004, pid=6760, tid=8140
#
# JRE version: Java(TM) SE Runtime Environment (8.0_31-b13) (build 1.8.0_31-b13)
# Java VM: Java HotSpot(TM) 64-Bit Server VM (25.31-b07 mixed mode windows-amd64 compressed oops)
# Problematic frame:
# V [jvm.dll+0x12f004]
#
# Failed to write core dump. Minidumps are not enabled by default on client versions of Windows
#
# If you would like to submit a bug report, please visit:
# http://bugreport.java.com/bugreport/crash.jsp
# ... Register to memory mapping: RAX=0x0000000000000000 is an unknown value
RBX=0x000000005af15000 is a thread
RCX=0x000000005af15000 is a thread
RDX=0x00000000d707b160 is an oop
java.lang.NoSuchFieldError
- klass: 'java/lang/NoSuchFieldError'
RSP=0x000000005bcce510 is pointing into the stack for thread: 0x000000005af15000
RBP=0x000000005bcceb80 is pointing into the stack for thread: 0x000000005af15000
RSI={method} {0x0000000056b83b18} 'run' '()V' in 'TestCaset1000$1'
RDI=0x0000000000000000 is an unknown value
R8 =0x0000000000000000 is an unknown value
R9 =0x0000000000000b80 is an unknown value
R10=0xfefefefefefefeff is an unknown value
R11=0x8080808080808080 is an unknown value
R12=0x000000005af15000 is a thread
R13=0x000000005ae58030 is an unknown value
R14=0x0000000000000000 is an unknown value
R15=0x00000000024388e0 is an unknown value Stack: [0x000000005bbd0000,0x000000005bcd0000], sp=0x000000005bcce510, free space=1017k
Native frames: (J=compiled Java code, j=interpreted, Vv=VM code, C=native code)
V [jvm.dll+0x12f004]
C [TraceCapture.dll+0x5086] callbackSingleStep+0x466
V [jvm.dll+0x1a7389]
V [jvm.dll+0x1aa34c]
V [jvm.dll+0xa9c23]
C 0x00000000025afddd ...

当中 TraceCapture.dll 就是我写的 JVMTI agent,大概能够推測到是 callbackSingleStep+0x466 这个地方出一错误,异常

java.lang.NoSuchFieldError。那么怎么找到这个位置呢?

这就涉及调试动态链接库文件了,调试的时候,在 callbackSingleStep 函数上加一个断点。调试时会停在这个断点上。

此时,首先查看 callbackSingleStep 的首地址,在 visual studio 2013 中把鼠标放在函数名上就能够显示出来,然后将这个地址添加

0x466,就找到了出错的位置的地址,再在 Call Stack 窗体中,右击 TraceCapture.dll 这一项进行反汇编。就进入了反汇编界面,

找到对应地址对应的函数语句就可以。

版权声明:本文博客原创文章,博客,未经同意,不得转载。

JVMTI 中间JNI系列功能,线程安全和故障排除技巧的更多相关文章

  1. 【FICO系列】SAP FI验证故障排除(调试)

    公众号:SAP Technical 本文作者:matinal 原文出处:http://www.cnblogs.com/SAPmatinal/ 原文链接:[FICO系列]SAP FI验证故障排除(调试) ...

  2. Java多线程系列--“JUC线程池”02之 线程池原理(一)

    概要 在上一章"Java多线程系列--“JUC线程池”01之 线程池架构"中,我们了解了线程池的架构.线程池的实现类是ThreadPoolExecutor类.本章,我们通过分析Th ...

  3. Java多线程系列--“JUC线程池”03之 线程池原理(二)

    概要 在前面一章"Java多线程系列--“JUC线程池”02之 线程池原理(一)"中介绍了线程池的数据结构,本章会通过分析线程池的源码,对线程池进行说明.内容包括:线程池示例参考代 ...

  4. linux高级编程基础系列:线程间通信

    linux高级编程基础系列:线程间通信 转载:原文地址http://blog.163.com/jimking_2010/blog/static/1716015352013102510748824/ 线 ...

  5. Java多线程系列--“JUC线程池”06之 Callable和Future

    概要 本章介绍线程池中的Callable和Future.Callable 和 Future 简介示例和源码分析(基于JDK1.7.0_40) 转载请注明出处:http://www.cnblogs.co ...

  6. Java多线程系列--“JUC线程池”04之 线程池原理(三)

    转载请注明出处:http://www.cnblogs.com/skywang12345/p/3509960.html 本章介绍线程池的生命周期.在"Java多线程系列--“基础篇”01之 基 ...

  7. Java多线程系列--“JUC线程池”05之 线程池原理(四)

    概要 本章介绍线程池的拒绝策略.内容包括:拒绝策略介绍拒绝策略对比和示例 转载请注明出处:http://www.cnblogs.com/skywang12345/p/3512947.html 拒绝策略 ...

  8. 死磕 java线程系列之线程池深入解析——普通任务执行流程

    (手机横屏看源码更方便) 注:java源码分析部分如无特殊说明均基于 java8 版本. 注:线程池源码部分如无特殊说明均指ThreadPoolExecutor类. 简介 前面我们一起学习了Java中 ...

  9. Java并发编程系列-(2) 线程的并发工具类

    2.线程的并发工具类 2.1 Fork-Join JDK 7中引入了fork-join框架,专门来解决计算密集型的任务.可以将一个大任务,拆分成若干个小任务,如下图所示: Fork-Join框架利用了 ...

随机推荐

  1. android 常见的解决(mdpi、hdpi 、xhdpi、xxhdpi )屏幕调整

    查询到执行的system service后,就能够在dumpsys后面加上service的名字,查看指定的service信息. adb shell dumpsys activity adb shell ...

  2. CocoStudio学习资源

    CocoStudio安装包及实例project:http://www.cocoachina.com/bbs/read.php?tid=154886 CocoStudio视频教程系列:http://mo ...

  3. hdu4185 Oil Skimming(偶匹配)

    <span style="font-family: Arial; font-size: 14.3999996185303px; line-height: 26px;"> ...

  4. RH253读书笔记(3)-Lab 3 Securing Networking

    Lab 3 Securing Networking Goal: To build skills with the Netfilter packet filter Sequence 1: Applyin ...

  5. POJ1458 Common Subsequence 【最长公共子序列】

    Common Subsequence Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 37614   Accepted: 15 ...

  6. ffmpeg和opencv 播放视频文件和显示器

    ffmpeg它是基于最新版本,在官网下载http://ffmpeg.zeranoe.com/builds/.编译时VS2010配置相关头文件及库的路径就可以.opencv的搭建參考上一个博客. 首先简 ...

  7. C和指针 (pointers on C)——第十章:结构和联合(下一个)锻炼

    //1.本章只为了刷存在演习.. . typedef struct phone { char * quhao; char * jiaohuantai; char * zhanhaoma; }; typ ...

  8. Team Foundation Server 2015使用教程--读取器tfs组的checkin权限修改

  9. Atitit..文件上传组件选择and最佳实践的总结(2)----HTTP

    Atitit..文件上传组件选型and最佳实践总结(2)----断点续传 1. 断点续传的原理 1 2. 怎样推断一个插件/控件是否支持断点续传?? 1 3. 经常使用的组件选型结果::马 1 4.  ...

  10. OpenGL路(四)自制的图形功能(立方体、汽缸、圆锥)

    #include <gl/glut.h> #include <gl/GLU.h> #include <gl/GL.h> #pragma comment(lib, & ...