当JNI代码在类加载器中使用env-> FindClass()时,Tomcat会出现段错误

时间:2015-06-02 11:02:19

标签: java tomcat java-native-interface classloader opensplice

我在运行使用OpenSplice DDS(6.1.0p5,PrismTech分发)在Tomcat(8.0.21)内部使用Oracle JRE(1.8u40)的Web应用程序时遇到了困难。

背景

我们的代码使用OpenSplice库dcpscj.jar,dcpssaj.jar,dlrlsaj.jar。出于许可和维护原因,它们托管在外部目录/opt/OpenSpliceDDS/V6.1.0p6/HDE/x86.linux2.6/jar中,而不是嵌入在通常的WEB-INF / lib中的WAR文件中。

setenv.sh

export CLASSPATH=/opt/OpenSpliceDDS/V6.1.0p6/HDE/x86.linux2.6/jar/dcpscj.jar:/opt/OpenSpliceDDS/V6.1.0p6/HDE/x86.linux2.6/jar/dcpssaj.jar:/opt/OpenSpliceDDS/V6.1.0p6/HDE/x86.linux2.6/jar/dlrlsaj.jar
export CATALINA_OPTS=-Djava.library.path=/opt/OpenSpliceDDS/V6.1.0p6/HDE/x86.linux2.6/lib
export LD_PRELOAD=/usr/java/jre/lib/i386/libjsig.so

根据tomcat classloading documentation,我还通过conf / catalina.properties中的common.loader属性成功提供了库。

问题

使用CLASSPATH和common.loader方法,在部署WAR时,Tomcat会一直与SIG_SEGV崩溃。

#
# A fatal error has been detected by the Java Runtime Environment:
#
#  SIGSEGV (0xb) at pc=0x0142043a, pid=17613, tid=2004876144
#
# JRE version: Java(TM) SE Runtime Environment (8.0_40-b25) (build 1.8.0_40-b25)
# Java VM: Java HotSpot(TM) Server VM (25.40-b25 mixed mode linux-x86 )
# Problematic frame:
# V  [libjvm.so+0x53543a]  get_method_id(JNIEnv_*, _jclass*, char const*, char const*, bool, Thread*)+0x7a
#
# Core dump written. Default location: //core or core.17613
#
# If you would like to submit a bug report, please visit:
#   http://bugreport.java.com/bugreport/crash.jsp
#

堆栈的顶部

V  [libjvm.so+0x53543a]  get_method_id(JNIEnv_*, _jclass*, char const*, char const*, bool, Thread*)+0x7a
V  [libjvm.so+0x5467ad]  jni_GetMethodID+0xbd
C  [libdcpssaj.so+0x1569e]  saj_cacheStructBuild+0x10e
C  [libdcpssaj.so+0x148ae]  saj_metaObject+0x9e
C  [libdcpssaj.so+0x14b76]  saj_copyCacheBuild+0x56
C  [libdcpssaj.so+0x14c34]  saj_copyCacheNew+0x94
C  [libdcpssaj.so+0x29dcf]  Java_org_opensplice_dds_dcps_FooTypeSupportImpl_jniRegisterType+0x21f
j  org.opensplice.dds.dcps.FooTypeSupportImpl.jniRegisterType(Ljava/lang/Object;LDDS/DomainParticipant;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)I+0
j  org.opensplice.dds.dcps.FooTypeSupportImpl.registerType(Ljava/lang/Object;LDDS/DomainParticipant;Ljava/lang/String;)I+17
j  org.example.dds.example_topic_typeTypeSupport.register_type(LDDS/DomainParticipant;Ljava/lang/String;)I+3

分析

仅当JAR位于WEB-INF / lib外部时才会出现此问题,如果它们是嵌入式的'在WEB-INF / lib中,Tomcat不会崩溃。

org.example.dds.example_topic_typeTypeSupport(匿名)是由OpenSplice生成的代码,我们将其打包为WEB-INF / lib中的单独JAR。

example_topic_typeTypeSupport调用FooTypeSupportImpl.registerType(),然后将类名作为IDL格式的字符串传递给" org :: example :: dds:example_topic_type"进入JNI部分saj_fooTypeSupport.c

很难理解,但我相信最终使用Java变体调用env-> FindClass,即org.example.dds.example_topic_type。这似乎是返回NULL,然后传递给jni_GetMethodID,导致段错误。

javaClass = (*(ctx->javaEnv))->FindClass (ctx->javaEnv, classDescriptor);

根据FindClass documentation,使用的类加载器是承载本机方法的类加载器。

  

FindClass定位与当前本机方法关联的类加载器;也就是说,声明本机方法的类的类加载器。如果本机方法属于系统类,则不涉及类加载器

这意味着类加载器是用于加载生活在dcpssaj.jar中的FooTypeSupportImpl的类加载器。这个类加载器无法看到生活在WEB-INF / lib / topics.jar中的主题定义。

Tomcat classloading documentation描述了每个模块的私有类加载器

  Bootstrap
      |
   System   <=== if dcpssaj.jar is loaded here then it can't see example_topic_type in topics.jar
      |
   Common   <=== if dcpssaj.jar is loaded here then it can't see example_topic_type in topics.jar
    /       
 Webapp1  <=== WEB-INF/lib/topics.jar containing example_topic_type

问题

  • 无论如何在Tomcat 中包含额外的JAR文件,而是否用于在WEB-INF / lib中加载其他JAR的相同的类加载器加载它们?我正在寻找基于干净配置的解决方案 - 我已经考虑过解决方案,包括符号链接或在部署时通过某些脚本将DDS JAR移植到WAR文件中。
  • 是否有配置OpenSplice DDS以避免此问题?

0 个答案:

没有答案