代码之家  ›  专栏  ›  技术社区  ›  Ogre Psalm33

JNI C++调试技术?

  •  4
  • Ogre Psalm33  · 技术社区  · 14 年前

    我有一个Linux C++应用程序,它创建一个JVM并使JNI调用。我刚接触JNI,到目前为止,我发现在开发过程中调试应用程序的唯一有效方法是通过尝试和错误。有什么技术可以用来调试臭名昭著的“致命错误被Java运行时环境检测到”Java虚拟机崩溃?我如何知道问题是我的代码还是真正的JVM bug?

    总的来说,到目前为止我所知道的最明显的事情是:

    • 在代码中,在继续之前,始终检查JNI调用返回的jobject、class和jmethodid值是否为空值。
    • 在适当的地方调用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->callObjectMethod()中快要死了。在深入到JVM代码之前,我检查了gdb中的所有参数,但没有看到任何明显的空值或奇怪的值。当然,所有的JNI类,比如Jobject,都是不透明的,所以我看不出它们的指针指向的是伪造的还是真实的数据。

    对于这类问题有什么建议吗?

    2 回复  |  直到 8 年前
        1
  •  4
  •   Ogre Psalm33    14 年前

    好的,下面是我如何处理我上面提到的问题。虽然有点乏味,但只要有足够的时间和精力,最终还是有了回报。

    1. 不要假设env->callmethod(jobj,meth_id,…)正在传递正确的值。如果这是崩溃的地方,那么很可能很难找到一些根本问题,但根本问题是错误的,例如正在传递的方法ID与正在传递给CallObjectMethod(…)的Jobject不匹配。我写了一个简单的助手方法 std::string getClassInfo(JNIEnv* env, jclass aJavaClass) 它得到一个类上的“toString”的方法,调用该方法,并将结果返回为STD::这告诉我一个物体是不是我想的那样。
    2. 在JNI调用之间随意地喷洒调试输出语句。尤其是输出类名(如通过上面的方法)将帮助您了解天气对象是您所认为的。
    3. 确保正在检查空方法ID,并在每个callMethod(…)之后调用env->exceptioncheck()。在callmethod(…)之后检查空值没有帮助,因为JNI不知道空值是否是有效的返回类型。
    4. 不要以为JNI会在第一次出现问题时崩溃。实际上,在实际崩溃之前,我通过几个JNI调用传递了错误的对象类型。请参阅3,以确保您尽早发现问题。
        2
  •  2
  •   Edric    8 年前

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