JNI C ++调试技术?

时间:2010-10-26 14:29:13

标签: c++ debugging jvm java-native-interface

我有一个Linux C ++应用程序,它创建一个JVM并进行JNI调用。我是JNI的新手,到目前为止,我发现在开发过程中调试应用程序的唯一有效方法是通过反复试验。有哪些技术可用于调试臭名昭着的“Java运行时环境已检测到致命错误”Java VM崩溃了?我怎么知道问题是我的代码还是真正的JVM错误?

总的来说,到目前为止,我所知道的显而易见的事情是:

  • 在代码中,始终检查从JNI调用返回的jobject,class和jmethodID值是否为NULL值,然后再继续。
  • 在适当的时候调用env-> ExceptionCheck()以确保没有待处理的异常。

目前,我遇到了错误报告文件中的堆栈跟踪不太有用的问题:

# A fatal error has been detected by the Java Runtime Environment:
#
#  SIGSEGV (0xb) at pc=0x00002b137a99db59, pid=19977, tid=47362673452544
#
# JRE version: 6.0_20-b02
# Java VM: Java HotSpot(TM) 64-Bit Server VM (16.3-b01 mixed mode linux-amd64 )
# Problematic frame:
# V  [libjvm.so+0x40fb59]
  ... <snip> ...
Stack: [0x00007fff1964f000,0x00007fff1974f000],  sp=0x00007fff1974e050,  free space=3fc0000000000000018k
Native frames: (J=compiled Java code, j=interpreted, Vv=VM code, C=native code)
V  [libjvm.so+0x40fb59]
V  [libjvm.so+0x3ecbe1]
C  [libDataFabric.so+0x1bb5b]  _Jv_JNIEnv::CallObjectMethod(__jobject*, _jmethodID*, ...)+0xe3
etc. ...

好的,所以我知道它在env-&gt; CallObjectMethod()中死了。在我深入JVM代码之前,我检查了GDB中的所有参数,但是我没有看到任何明显的NULL或奇怪的值。当然,所有JNI类,例如jobject,都是无用的,所以我看不出它们的指针是指向伪造的还是真实的数据。

针对此类问题的任何提示/建议/想法?

2 个答案:

答案 0 :(得分:4)

好的,这就是我如何解决上面提到的问题。有点乏味,但是,如果有足够的时间和精力,它最终会得到回报。

  1. 不要认为env-&gt; CallMethod(jobj,meth_id,...)正在传递正确的值。如果这是崩溃的地方,那么一些难以发现但基本问题出错的可能性很高,例如传递的methodId与传递给CallObjectMethod(...)的jobject不匹配。我写了一个简单的帮助器方法std::string getClassInfo(JNIEnv* env, jclass aJavaClass),它在类上获取“toString”的MethodID,调用该方法,并将结果作为std :: string返回。这告诉我天气是我认为的对象。
  2. 在JNI调用之间自由地传递调试输出语句。特别是输出类名(例如通过上述方法)将帮助您确定天气对象是您认为的。
  3. 确保在每个CallMethod(...)之后检查null methodID并调用env-&gt; ExceptionCheck()。在CallMethod(...)之后检查null将无济于事,因为JNI无法知道null是否是有效的返回类型。
  4. 不要认为JNI会在出现问题时首先崩溃。我实际上在实际崩溃之前通过几个JNI调用传递了错误的对象类型。请参阅#3以确保您及早发现问题。

答案 1 :(得分:2)

请注意,在Linux上,JVM本身使用SEGV信号来指示垃圾收集器应该运行。我在gdb中使用“handle SIGSEGV pass noprint nostop”让JVM处理这些事情。