java - JNI Linux 段错误

标签 java c++ linux java-native-interface jnienv

我的 JNI 库在 Windows 上完美运行,但是在 Linux 上我总是遇到奇怪的段错误。

siginfo: si_signo: 11 (SIGSEGV), si_code: 1 (SEGV_MAPERR), si_addr: 0x0000000000000000

崩溃文件中的堆栈裂纹是这样的:

C  [libfmodjavaL.so+0xfb8c]  JNIEnv_::GetStaticObjectField(_jclass*, _jfieldID*)+0x18
C  [libfmodjavaL.so+0xf72b]  Logger::sendToSystemOut(bool, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >)+0x75
C  [libfmodjavaL.so+0xf7c2]  Logger::log(char const*)+0x4c
C  [libfmodjavaL.so+0xd70d]  fmodDebugCallback(unsigned int, char const*, int, char const*, char const*)+0x127

看来是在调用 Logger 类中的 GetStaticObject 字段时崩溃了。这就是那个方法:

void Logger::sendToSystemOut(bool error, std::string message) {
    JNIEnv* jni = FMODWrapper::utils->getJNI();

    jobject printStream;
    if (error) {
        printStream = jni->GetStaticObjectField(this->systemClass, this->errFieldID);
    } else {
        printStream = jni->GetStaticObjectField(this->systemClass, this->outFieldID);
    }

    jobject messageString = jni->NewStringUTF(message.c_str());
    jni->CallObjectMethod(printStream, this->printlnMethodID, messageString);
}

所以我猜测存储这些字段的类和字段 ID 是不正确的。但奇怪的是,当我的库启动时,我会得到日志输出,甚至是来自调用 fmodDebugCallback 的 FMOD。

Logger::Logger(const char* name) {
    this->name = name;

    JNIEnv* jni = FMODWrapper::utils->getJNI();

    this->systemClass = FMODWrapper::utils->findClass("java/lang/System");
    this->outFieldID = jni->GetStaticFieldID(this->systemClass, "out", "Ljava/io/PrintStream;");
    this->errFieldID = jni->GetStaticFieldID(this->systemClass, "err", "Ljava/io/PrintStream;");

    jclass printStreamClass = FMODWrapper::utils->findClass("java/io/PrintStream");
    this->printlnMethodID = jni->GetMethodID(printStreamClass, "println", "(Ljava/lang/String;)V");
}

因此,日志记录在 Windows 上完美运行,但一段时间后在 Linux 上崩溃。在 Fedora 29 64 位上使用 g++ 编译。

更新:我获取 JNIEnv* 的方法

JNIEnv* Utils::getJNI() {
    JNIEnv* jni;

    int getEnvResult = FMODWrapper::jvm->GetEnv((void**) &jni, JNI_VERSION_1_6);

    if (getEnvResult == JNI_EDETACHED) {
        FMODWrapper::jvm->AttachCurrentThread(ANDROID_VOIDPP_CAST &jni, nullptr);
    }

    return jni;
}

更新 2:自从我收到日志消息以来,代码本身可以正常工作到一定程度。可能与线程有关? https://hastebin.com/kuzefuwawu.txt

最佳答案

systemClass、errFieldId 和 outFieldID 都是从不同的 JNIEnv 获取的。

JNIEnv 无法缓存: Keeping a global reference to the JNIEnv environment

正如它不能被缓存一样,您不能存储从您不应再使用的其他 JNIEnv 获取的 id,也不应该使用来自它的任何内容。您需要从当前有效的 JNIEnv 中获取它们。

关于java - JNI Linux 段错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55768112/

相关文章:

java - Java 安全管理器的使用

java - 使用 USB 电缆打印问题

java - 在带有 Java 的 Matlab 中使用 OpenGL?

c++ - 是否有任何库可以在 C++ 中使用 HFile 格式

c++ - 将资源文件嵌入可执行文件的性能

php 我的爬虫在一段时间后崩溃段错误错误

linux - sed 行将周围的冒号更改为 bash 中的点

java - 基本数组中随机生成的数字

当提供从网络接收到的字符串时,Curses printw() 将仅打印换行符

c++ - 使用 WM_COPYDATA 消息发送用户定义的结构