You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

创建Java对象时JVM崩溃:构造函数存在却提示找不到

解决JNI创建String对象时JVM崩溃的问题

问题根源分析

你遇到的崩溃看似是找不到构造函数,但实际代码里有两个致命问题:

  1. 野指针引用
    原代码中this->object = &newObject;是严重错误:newObject是构造函数内的局部栈变量,函数执行结束后这个变量会被销毁,保存它的地址会让this->object变成野指针。后续对这个指针的任何操作都会直接导致JVM崩溃,甚至可能掩盖真正的错误信息(比如GetMethodID失败的问题)。

  2. 缺少JNI错误检查
    调用GetMethodID和NewObjectV后没有判断返回值是否为NULL,也没有检查JNI异常。如果GetMethodID因为类引用错误(比如javaClass->getClass()没拿到正确的java.lang.String类)等原因失败,直接调用NewObjectV会触发崩溃。

修复后的代码示例

1. 修正JavaObject构造函数

JavaObject(jclass klass, const char *signature, ...) {
    std::cout << "constructing" << std::endl;
    va_list arg;
    va_start(arg, signature);
    
    // 获取构造函数ID并检查错误
    jmethodID constructor = client->env->GetMethodID(klass, "<init>", signature);
    if (constructor == nullptr) {
        if (client->env->ExceptionCheck()) {
            client->env->ExceptionDescribe(); // 打印JNI异常详情
            client->env->ExceptionClear();
        }
        std::cerr << "Failed to get String constructor method ID" << std::endl;
        this->object = nullptr;
        va_end(arg);
        return;
    }

    // 创建对象并检查错误
    jobject newObject = client->env->NewObjectV(klass, constructor, arg);
    if (newObject == nullptr) {
        if (client->env->ExceptionCheck()) {
            client->env->ExceptionDescribe();
            client->env->ExceptionClear();
        }
        std::cerr << "Failed to create String object" << std::endl;
        this->object = nullptr;
        va_end(arg);
        return;
    }

    // 保存全局引用(如果需要长期持有对象),避免局部引用被回收
    this->object = client->env->NewGlobalRef(newObject);
    // 释放临时局部引用
    client->env->DeleteLocalRef(newObject);

    va_end(arg);
}

2. 修正String类构造函数

确保获取的是正确的java.lang.String类,建议直接用FindClass替代javaClass->getClass(),避免类引用错误:

String(jcharArray v1) : JavaObject(client->env->FindClass("java/lang/String"), "([C)V", v1) {}

关键注意事项

  • JNI中局部引用(比如NewObjectV返回的newObject)会在当前JNI方法返回后被JVM自动回收,如果你的JavaObject需要长期持有对象,必须调用NewGlobalRef创建全局引用,用完后记得调用DeleteGlobalRef释放。
  • 任何JNI函数调用后都要检查返回值和JNI异常,这是排查JNI问题的核心手段。

内容的提问来源于stack exchange,提问作者Derek Li

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.09 01:20:27