代码之家  ›  专栏  ›  技术社区  ›  John Smith

JNA与64位libmx崩溃。所以在Linux上

  •  0
  • John Smith  · 技术社区  · 2 年前

    我有一个遗留的Java应用程序,它使用JNA与Matlab C Matrix API进行交互。

    /**
     * Load a MAT-file. Must be synchronized because of native libraries calls.
     *
     * @param file MAT file
     * @return map with the variables in the MAT file
     */
    public static synchronized Map<String, MObj> load(final File file) {
        if (file == null) {
            throw new InvalidMatFileException(null, ERROR_MSG_FILE_NOT_FOUND);
        }
        if (!file.isFile()) {
            throw new InvalidMatFileException(file.getName(), ERROR_MSG_FILE_NOT_FOUND);
        }
        final Map<String, MObj> vars = new HashMap<String, MObj>();
        final Pointer matfile = MAT_LIB.matOpen(file.getAbsolutePath(), "r");
        if (matfile == null) {
            throw new InvalidMatFileException(file.getName(), ERROR_MSG_NOT_A_PROPER_MAT_FILE);
        }
        for (;;) {
            final PointerByReference name = new PointerByReference();
            final Pointer ar = MAT_LIB.matGetNextVariable(matfile, name);
            if (ar == null) {
                break;
            }
            final MObj obj = ToJava.convert(MX_LIB, ar);
            MX_LIB.mxDestroyArray(ar);
            vars.put(name.getValue().getString(0), obj);
        }
        MAT_LIB.matClose(matfile);
        return vars;
    }
    
    //ToJava class has the following methods that are called from the code above
     /**
     * Convert a single mxArray
     *
     * @param mx MX library
     * @param ar mxArray
     * @return MObj instance
     */
    public static MObj convert(MX mx, Pointer ar) {
        final ToJava tr = new ToJava(mx);
        tr.transform(ar);
        return tr.obj;
    }
    
    /**
     * Top-level transform
     *
     * @param ar mxArray
     */
    private void transform(Pointer ar) {
        final ClassID classID = ClassID.valueOf(mx.mxGetClassID(ar));
        switch (classID) {
    
        case DOUBLE:
            transformDoubleArray(ar);
            break;
    
    

    for循环内部

    ToJava.convert
    电话
    mx.mxGetClassID(ar)
    

    在引擎盖下。这是 defined in the api

    mxClassID mxGetClassID(const mxArray *pm);
    

    哪里 mxClassID 是枚举。这在JNA中映射为

    int mxGetClassID(Pointer ar);
    

    这正是导致下面崩溃的代码片段

    #
    # A fatal error has been detected by the Java Runtime Environment:
    #
    #  SIGSEGV (0xb) at pc=0x00007fbb7fcd45f0, pid=13363, tid=140445588428544
    #
    # JRE version: 6.0_45-b06
    # Java VM: Java HotSpot(TM) 64-Bit Server VM (20.45-b01 mixed mode linux-amd64 compressed oops)
    # Problematic frame:
    # C  [libmx.so+0x615f0]  matrix::detail::noninlined::mx_array_api::mxGetClassID(mxArray_tag const*)+0x0
    Register to memory mapping:
    
    RAX=0x0000000000000000 is an unknown value
    RBX=0x0000000000000008 is an unknown value
    RCX=0x00007fbc04252a7a is an unknown value
    RDX=0x00007fbc04252a7a is an unknown value
    RSP=0x00007fbc09686888 is pointing into the stack for thread: 0x00007fbc04006800
    RBP=0x00007fbc09686890 is pointing into the stack for thread: 0x00007fbc04006800
    RSI=0x00007fbc04252a7a is an unknown value
    RDI=0x0000000000000000 is an unknown value
    R8 =0x00007fbc04252a7a is an unknown value
    R9 =0x00007fbc04252a95 is an unknown value
    R10=0x0000000000000000 is an unknown value
    R11=0x00007fbb7fd46800: mxGetClassID+0 in /var/opt/Matlab_MCR/v91/bin/glnxa64/libmx.so at 0x00007fbb7fc73000
    R12=0x00007fbc096869d0 is pointing into the stack for thread: 0x00007fbc04006800
    R13=0x0000000000000008 is an unknown value
    R14=0x0000000000000001 is an unknown value
    R15=0x00007fbc096869b0 is pointing into the stack for thread: 0x00007fbc04006800
    
     Stack: [0x00007fbc09589000,0x00007fbc0968a000],  sp=0x00007fbc09686888,  free space=1014k
    Native frames: (J=compiled Java code, j=interpreted, Vv=VM code, C=native code)
    C  [libmx.so+0x615f0]  matrix::detail::noninlined::mx_array_api::mxGetClassID(mxArray_tag const*)+0x0
    
    Java frames: (J=compiled Java code, j=interpreted, Vv=VM code)
    j  com.sun.jna.Native.invokeInt(Lcom/sun/jna/Function;JI[Ljava/lang/Object;)I+0
    j  com.sun.jna.Function.invoke([Ljava/lang/Object;Ljava/lang/Class;ZI)Ljava/lang/Object;+211
    j  com.sun.jna.Function.invoke(Ljava/lang/reflect/Method;[Ljava/lang/Class;Ljava/lang/Class;[Ljava/lang/Object;Ljava/util/Map;)Ljava/lang/Object;+271
    j  com.sun.jna.Library$Handler.invoke(Ljava/lang/Object;Ljava/lang/reflect/Method;[Ljava/lang/Object;)Ljava/lang/Object;+390
    j  com.sun.proxy.$Proxy12.mxGetClassID(Lcom/sun/jna/Pointer;)I+16
    

    总而言之,

    • Linux 32位MCR(matlab编译器运行时)+32位Java6/7/8: 作品
    • Windows 32位MCR(matlab编译器运行时)+32位Java6/7/8: 作品
    • Windows 64位MCR(matlab编译器运行时)+64位Java6/7/8: 作品
    • Linux 64位MCR(matlab编译器运行时)+64位Java6/7/8:JNA崩溃

    到目前为止,我尝试设置LD\u LIBRARY\u路径以及java。图书馆路径,并同时指向文件系统上的MCR位置

    /var/opt/Matlab_MCR/v91/runtime/glnxa64:/var/opt/Matlab_MCR/v91/bin/glnxa64:/var/opt/Matlab_MCR/v91/sys/os/glnxa64
    

    有人知道如何进一步排除故障吗?

    0 回复  |  直到 2 年前
        1
  •  1
  •   John Smith    2 年前

    这个问题中的代码通过JNA调用Matlab编译器运行时公开的函数。结果是 对于64位体系结构,Matlab端的接口已更改。他们在本机API签名中使用mwSize类型,而我们的JNA映射使用int。在mwSize等效于size\u t的64位机器上,int将为32位。因此,JNA映射和本机API签名不再匹配。在通过JNA反复调用这些函数之后,它甚至会导致JNA崩溃。

    解决方案的方向是在Java代码上用64位整数替换int。这可以通过扩展JNA提供的名为IntegerType的抽象类并在适用的情况下使用该扩展类来实现

    Matlab参考文章: https://nl.mathworks.com/help/matlab/matlab_external/upgrading-mex-files-to-use-64-bit-api.html