2016-02-23 20 views
2

我已經使用JNI,JNA,BridJ和JavaCPP多次重建我的Java/C++項目,並且每次遇到隨機(不可預知的)分段錯誤。我已經驗證了使用這個庫的pure-C++可執行文件永遠不會導致分段錯誤,並且在BridJ的情況下,通過顯式調用它將其縮小到Java的垃圾回收器。JNA/BridJ etc中的分段錯誤

一個想到的是,這些庫創建調用freedelete,當他們得到垃圾收集(通過finalize),而不是治療的指針是C++的回報作爲借用引用Java端指針的對象,因爲他們應該在這個應用程序。我已經嘗試了一個額外的測試(未在下面展示):我將API中的每個指針都轉換爲int64_tlong,在Java中),並在C++中明確地轉換爲適當的類型。我仍然看到罕見的段錯誤。

所以我的問題是廣泛的:什麼可能導致這個問題?我會接受使用JNA或BridJ的答案,因爲我可以輕鬆地在這兩者之間切換。我想我錯過了一個根本性的問題,因爲這個問題在我嘗試過的所有庫中都非常普遍。

具體而言,這是我的JNA版本。我正在鏈接CERN ROOT庫。 RootTreeReader.h是:

#ifndef ROOTTREEREADER_H 
#define ROOTTREEREADER_H 

#include <TFile.h> 
#include <TTreeReader.h> 
#include <TTreeReaderValue.h> 
#include <TTreeReaderArray.h> 

using namespace ROOT::Internal; 

extern "C" { 
    TFile *newFile(const char *fileLocation); 
    TTreeReader *newReader(TFile *file, const char *treeLocation); 
    bool readerNext(TTreeReader *reader); 

    TTreeReaderValueBase *newValue_float(TTreeReader *reader, const char *name); 

    float getValue_float(TTreeReaderValueBase *value); 
} 

#endif // ROOTTREEREADER_H 

RootTreeReader.cpp是:

#include <string> 

#include "RootTreeReader.h" 

TFile *newFile(const char *fileLocation) { 
    return TFile::Open(fileLocation); 
} 

TTreeReader *newReader(TFile *file, const char *treeLocation) { 
    return new TTreeReader(treeLocation, file); 
} 

bool readerNext(TTreeReader *reader) { 
    return reader->Next(); 
} 

TTreeReaderValueBase *newValue_float(TTreeReader *reader, const char *name) { 
    return new TTreeReaderValue<float>(*reader, name); 
} 

float getValue_float(TTreeReaderValueBase *value) { 
    return *((float*)value->GetAddress()); 
} 

他們的Makefile

all: RootTreeReader.cpp 
    mkdir -p ../../../target/native/linux-x86-64 
    g++ RootTreeReader.cpp -o ../../../target/native/linux-x86-64/libRootTreeReader.so \ 
     -fPIC -shared \ 
     -Wl,--no-as-needed $(shell root-config --cflags --ldflags --libs) -lTreePlayer 

JNAerator生成以下RootTreeReaderLibrary.java:

package org.dianahep.scaroot; 
import com.sun.jna.Library; 
import com.sun.jna.Native; 
import com.sun.jna.NativeLibrary; 
import com.sun.jna.Pointer; 
import com.sun.jna.PointerType; 
/** 
* JNA Wrapper for library <b>RootTreeReader</b><br> 
* This file was autogenerated by <a href="http://jnaerator.googlecode.com/">JNAerator</a>,<br> 
* a tool written by <a href="http://ochafik.com/">Olivier Chafik</a> that <a href="http://code.google.com/p/jnaerator/wiki/CreditsAndLicense">uses a few opensource projects.</a>.<br> 
* For help, please visit <a href="http://nativelibs4java.googlecode.com/">NativeLibs4Java</a> , <a href="http://rococoa.dev.java.net/">Rococoa</a>, or <a href="http://jna.dev.java.net/">JNA</a>. 
*/ 
public interface RootTreeReaderLibrary extends Library { 
    public static final String JNA_LIBRARY_NAME = "RootTreeReader"; 
    public static final NativeLibrary JNA_NATIVE_LIB = NativeLibrary.getInstance(RootTreeReaderLibrary.JNA_LIBRARY_NAME); 
    public static final RootTreeReaderLibrary INSTANCE = (RootTreeReaderLibrary)Native.loadLibrary(RootTreeReaderLibrary.JNA_LIBRARY_NAME, RootTreeReaderLibrary.class); 
    /** 
    * Original signature : <code>TFile* newFile(const char*)</code><br> 
    * <i>native declaration : src/main/cpp/RootTreeReader.h:5</i><br> 
    * @deprecated use the safer methods {@link #newFile(java.lang.String)} and {@link #newFile(com.sun.jna.Pointer)} instead 
    */ 
    @Deprecated 
    RootTreeReaderLibrary.TFile newFile(Pointer fileLocation); 
    /** 
    * Original signature : <code>TFile* newFile(const char*)</code><br> 
    * <i>native declaration : src/main/cpp/RootTreeReader.h:5</i> 
    */ 
    RootTreeReaderLibrary.TFile newFile(String fileLocation); 
    /** 
    * Original signature : <code>TTreeReader* newReader(TFile*, const char*)</code><br> 
    * <i>native declaration : src/main/cpp/RootTreeReader.h:6</i><br> 
    * @deprecated use the safer methods {@link #newReader(org.dianahep.scaroot.RootTreeReaderLibrary.TFile, java.lang.String)} and {@link #newReader(org.dianahep.scaroot.RootTreeReaderLibrary.TFile, com.sun.jna.Pointer)} instead 
    */ 
    @Deprecated 
    RootTreeReaderLibrary.TTreeReader newReader(RootTreeReaderLibrary.TFile file, Pointer treeLocation); 
    /** 
    * Original signature : <code>TTreeReader* newReader(TFile*, const char*)</code><br> 
    * <i>native declaration : src/main/cpp/RootTreeReader.h:6</i> 
    */ 
    RootTreeReaderLibrary.TTreeReader newReader(RootTreeReaderLibrary.TFile file, String treeLocation); 
    /** 
    * Original signature : <code>bool readerNext(TTreeReader*)</code><br> 
    * <i>native declaration : src/main/cpp/RootTreeReader.h:7</i> 
    */ 
    byte readerNext(RootTreeReaderLibrary.TTreeReader reader); 
    /** 
    * Original signature : <code>TTreeReaderValueBase* newValue_float(TTreeReader*, const char*)</code><br> 
    * <i>native declaration : src/main/cpp/RootTreeReader.h:9</i><br> 
    * @deprecated use the safer methods {@link #newValue_float(org.dianahep.scaroot.RootTreeReaderLibrary.TTreeReader, java.lang.String)} and {@link #newValue_float(org.dianahep.scaroot.RootTreeReaderLibrary.TTreeReader, com.sun.jna.Pointer)} instead 
    */ 
    @Deprecated 
    RootTreeReaderLibrary.TTreeReaderValueBase newValue_float(RootTreeReaderLibrary.TTreeReader reader, Pointer name); 
    /** 
    * Original signature : <code>TTreeReaderValueBase* newValue_float(TTreeReader*, const char*)</code><br> 
    * <i>native declaration : src/main/cpp/RootTreeReader.h:9</i> 
    */ 
    RootTreeReaderLibrary.TTreeReaderValueBase newValue_float(RootTreeReaderLibrary.TTreeReader reader, String name); 
    /** 
    * Original signature : <code>float getValue_float(TTreeReaderValueBase*)</code><br> 
    * <i>native declaration : src/main/cpp/RootTreeReader.h:11</i> 
    */ 
    float getValue_float(RootTreeReaderLibrary.TTreeReaderValueBase value); 
    public static class TFile extends PointerType { 
     public TFile(Pointer address) { 
      super(address); 
     } 
     public TFile() { 
      super(); 
     } 
    }; 
    public static class TTreeReader extends PointerType { 
     public TTreeReader(Pointer address) { 
      super(address); 
     } 
     public TTreeReader() { 
      super(); 
     } 
    }; 
    public static class TTreeReaderValueBase extends PointerType { 
     public TTreeReaderValueBase(Pointer address) { 
      super(address); 
     } 
     public TTreeReaderValueBase() { 
      super(); 
     } 
    }; 
} 

和我稱之爲這樣的:

Native.setProtected(true) 
println("Native.isProtected", Native.isProtected) // it's true on Linux; I've tried this with and without 

val lib = RootTreeReaderLibrary.INSTANCE 

println("one") 
val file = lib.newFile("TrackResonanceNtuple.root") 
println("two") 
val reader = lib.newReader(file, "TrackResonanceNtuple/twoMuon") 
println("three") 
val mass = lib.newValue_float(reader, "mass_mumu") 
println("four") 
var counter = 0 
while (lib.readerNext(reader) > 0) { 
    val num = lib.getValue_float(mass) 
    println(num) 
    counter += 1 
    // if (counter % 1000 == 0) { 
    // println("gc start") 
    // System.gc() 
    // println("gc end") 
    // } 
} 
println("five") 

它出現segfaults 很少有或沒​​有明確的垃圾收集器調用。 Bridjan版本的這段錯誤很少沒有和頻繁與顯式垃圾收集器調用。

+0

JNA將只釋放它已經分配的內存,並且它在非常明確定義的位置執行(參見'Native.dispose()',它引用它們全部)。您可以選擇性地禁用這些處理方法中的每一種,以確定是否涉及其中的任何一種。 – technomage

+0

你有我可以看看的JavaCPP版本嗎? –

+0

我試過JavaCPP 1.1,雖然上面的例子是JNA。 –

回答

4

快速修復:

export LD_PRELOAD=/path/to/libjsig.so 

的問題是,歐洲核子研究中心ROOT嘗試安裝的處理程序相同的信號JDK。Oracle建議預加載libjsig.so,它提供了一個「信號鏈接工廠」,要解決的問題,這些類型:吉姆

https://docs.oracle.com/javase/6/docs/technotes/guides/vm/signal-chaining.html

編輯:

專門爲ROOT框架,可以通過調用

gSystem->ResetSignals(); 

的討論可以在此ROOT留言板中找到關閉信號處理:https://root.cern.ch/phpBB3/viewtopic.php?t=8231