是否可以使用JNI API从JNI方法中创建JVM?
我试图使用JNI函数"JNI_CreateJavaVM()"来做到这一点,但它不起作用(函数保持返回小于零的值).
这是我正在使用的基本代码(C++):
JNIEnv *env;
JavaVM *jvm;
jint res;
#ifdef JNI_VERSION_1_2
JavaVMInitArgs vm_args;
JavaVMOption options[2];
options[0].optionString =
"-Djava.class.path=" USER_CLASSPATH;
options[1].optionString = "-verbose:jni";
vm_args.version = JNI_VERSION_1_2;
vm_args.options = options;
vm_args.nOptions = 2;
vm_args.ignoreUnrecognized = JNI_TRUE;
/* Create the Java VM */
res = JNI_CreateJavaVM(&jvm, (void**)&env, &vm_args);
#else
JDK1_1InitArgs vm_args;
char classpath[1024];
vm_args.version = 0x00010001;
JNI_GetDefaultJavaVMInitArgs(&vm_args);
/* Append USER_CLASSPATH to the default system class path */
sprintf(classpath, "%s%c%s",
vm_args.classpath, PATH_SEPARATOR, USER_CLASSPATH);
vm_args.classpath = classpath;
/* Create the Java VM */
res …
Run Code Online (Sandbox Code Playgroud) 我试图跟踪JVM中所有对象的分配.
在有关分配剖析器的几个文档中,有人提到最简单的方法是:添加invokestatic Tracker.trackAllocation()V
指令java/lang/Object.<init>
(通常它由单个return
指令组成,我们invokestatic
在它之前添加,因此现在是2个指令).
(我知道这种方法很慢,不会跟踪数组分配,但我想从最简单的解决方案开始.另外,我不会将对已分配对象的引用传递给跟踪器,但稍后会添加.)
类文件在onClassLoaded挂钩中使用JVM TI代理进行检测.
但是,添加了invokestatic
指令JVM与segfault崩溃后.Tracker对象被添加到bootstrap类加载器中,因此它应该在任何阶段都可见.我尝试添加nop
而不是invokestatic
,并且JVM与修改后的Object类一起工作正常.所以问题特别在于调用一些静态方法.
我还试图检测应用程序(不是基础的一部分)类,它工作正常 - 跟踪器被调用,没有发生崩溃.此外,我尝试在2点重新定义Object:当它最初加载(第一个加载的类)时,或者在vmInit事件之后(当加载所有基类并且解除对jni的限制时).
关于检测java.lang.Object有什么我遗漏的吗?
代理的代码在这里:https: //gist.github.com/Korobochka/3bf2f906f6ab85b22dec (错误检查被剥离,更改类的代码也不包括在内,但它适用于其他类)
为了支持更好的分析数据,我希望我的JVMTI代理能够启用几个JVM标志.有问题的代理是Honest-Profiler,它只能在启动时加载.
我想启用标志: -XX:+UnlockDiagnosticVMOptions -XX:+DebugNonSafepoints
我正在编写JVMTI代码来编写Java程序,这主要是使用函数AsyncGetCallTrace以固定的时间间隔从随机线程获取堆栈跟踪.因此,我能够获得CallTrace结构,每个结构都包含一个CallFrame结构数组,其中包含有关堆栈跟踪中各个帧的数据.具体来说,这些数据包括:jmethodID method_id(框架所在的java方法的ID),以及:jint lineno(.class文件中方法的BCI,据我所知文档).我似乎找不到使用JVMTI框架将这个"lineno"转换为相应的源代码行号的方法(参见文件jvmti.h,位于/ usr/lib/jvm/java-6-sun/include,至少在Linux上).实际上,即使在JVMTI框架之外,http://jakarta.apache.org/bcel/apidocs/org/apache/bcel/classfile/LineNumberTable.html,但即使这可能不是我想要的,并需要额外的安装,并要求我处理数据,这是由C++ JMVTI代码生成的,使用单独的Java程序.
如果有人知道如何从JVMTI内部(甚至以任何方式)将BCI转换为源代码行号,请帮忙!
[如果有人非常了解这个领域,请告诉我,因为我还有一些问题要问这个过程.]
lsof
是一个很好的Unix工具,显示所有当前打开的文件句柄.
有没有人知道一个类似的工具,可以在运行的JVM中显示所有打开的文件(通过JVMTI或任何类似的界面)?
在这种特殊情况下,只要知道哪个类有句柄打开就足够了.方法/行甚至整个链到GC根目录都很棒,但处理程序所有者类已经是一个好的开始.
我知道我可以进行堆转储,在分析器中打开并找到它,但这是一项繁琐的工作,特别是对于大堆.
我正在寻找可能的JDI API来在执行期间的任意点暂停JVM.查看BreakPointRequest createBreakpointRequest方法需要一个特定的位置.是否有任何其他API不需要位置或某种方式来获取可以传递以创建断点的当前位置.
我基本上寻找一种方法来附加和暂停应用程序,然后使用JVMTI代理接收BreakPoint事件的回调以执行进一步处理.谢谢
我目前正在为Java 1.7构建一个本机JVMTI代理.问题是我需要索引有关特定Java对象实例的一些数据.所以我的问题是我可以使用jobject类型的值作为对象的实例ID来检索我的索引数据吗?
我已经查找了有关jobject类型的语义的任何信息.它是Object的内存位置的指针吗?它是一个堆栈指针地址吗?它是JVM内部结构的地址吗?所以我无法弄清楚jobject的值是否是Java对象生命中唯一且不可变的.
谢谢你的帮助.
编辑
根据JNI在这里找到的规范,jobject似乎是Object实例的指针.
使用时Java Attach API
,我在Linux上遇到以下链接错误(仅在不同的机器上试过):
Exception in thread "main" java.lang.UnsatisfiedLinkError: sun.tools.attach.WindowsAttachProvider.tempPath()Ljava/lang/String;
at sun.tools.attach.WindowsAttachProvider.tempPath(Native Method)
at sun.tools.attach.WindowsAttachProvider.isTempPathSecure(WindowsAttachProvider.java:74)
at sun.tools.attach.WindowsAttachProvider.listVirtualMachines(WindowsAttachProvider.java:58)
at com.sun.tools.attach.VirtualMachine.list(VirtualMachine.java:134)
at sun.tools.jconsole.LocalVirtualMachine.getAttachableVMs(LocalVirtualMachine.java:151)
at sun.tools.jconsole.LocalVirtualMachine.getAllVirtualMachines(LocalVirtualMachine.java:110)
...
Run Code Online (Sandbox Code Playgroud)
有趣的是,在Solaris和Windows上,它开箱即用.
我尝试了几种指定的组合java.library.path
指向包含libattach.so
但没有运气的目录.
这有什么不对?
作为一个额外的问题:
有没有办法看到哪个本地库实际上绑定到java类?
Java类文件格式支持称为“源调试扩展名”的属性(请参见Java语言规范§4.7.11“ SourceDebugExtension
属性”)。
在支持JVMTI这方面的JVM中,您可以使用来查询此字符串jvmtiError GetSourceDebugExtension(jvmtiEnv *, jclass, char **)
。
我的问题是,是否存在一种使用普通javac
语言和Java语言将“源调试扩展”信息嵌入.class
文件的方法。核心Java语言中似乎没有可以执行此操作的注释(的javadocjava.lang.Annotation
的“所有已知的实现类”列表中没有明显的候选者)。
我有自己的 JDI 调试器,它toString
在某些对象上调用该方法:
com.sun.jdi.ObjectReferenceobject object = ...
ThreadReference threadRef = frameProxy.threadProxy().getThreadReference();
Value value = object.invokeMethod(threadRef, toStringMethod,
Collections.EMPTY_LIST, ObjectReference.INVOKE_SINGLE_THREADED);
Run Code Online (Sandbox Code Playgroud)
问题是即使在 toString() 方法中没有设置断点, invokeMethod 也永远不会终止,所以我的调试器挂起。例如,当我在Double
对象上调用 this 时会发生这种情况。
如何invokeMethod
在一段时间后终止执行?
更新:我尝试实现我自己的Double
对象并System.out.println()
在方法的开头和结尾放置了一些语句,toString()
看起来该方法执行得很好,但由于某种原因调试器没有收到结果。也许这是 JDI 中的一个错误,因为有很多这样的错误,但我不是在为此寻找解决方案,我只是在寻找一种方法来中止执行,invokeMethod()
如果它花费太多时间。
更新 2:我尝试了ThierryB 的建议,但我只能frameProxy.threadProxy().stop(object);
在经理线程中调用。并且管理器线程被阻塞,invokeMethod()
因此它不会执行我的命令。我试过这样的事情:
boolean[] isFinished = new boolean[2];
isFinished[0] = false;
DebuggerManagerThreadImpl managerThread = debugProcess.getManagerThread();
new Thread(() - > {
try {
Thread.sleep(2000);
if (!isFinished[0]) {
System.out.println("Invoked"); …
Run Code Online (Sandbox Code Playgroud) jvmti ×10
java ×9
jvm ×3
debugging ×2
jdi ×2
.class-file ×1
annotations ×1
breakpoints ×1
line-numbers ×1
linux ×1
lsof ×1