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

调用C++ Native方法时JVM崩溃,求排查解决方案

排查与修复JNI调用导致的JVM崩溃问题

核心问题分析

从错误信息EXCEPTION_ACCESS_VIOLATION(0xc00000005)和~BufferBlob::jni_fast_GetCharField来看,崩溃是JNI层访问空指针导致的,且断点未命中needTransform第一行,说明问题大概率出在Native方法注册阶段或参数传递前的非法内存访问。以下是针对性的排查与修复步骤:


1. 修正JNIEnv的非法强制转换

问题点

你直接将标准JNIEnv*强制转换为自定义的CustomJEnv*:

auto* tools = (CustomJEnv*)env;

如果CustomJEnv不是JNIEnv的合法子类,或GetEnv返回的是未初始化的无效指针,会直接触发内存访问错误,且崩溃发生在进入needTransform方法之前,导致断点无法命中。

修复

替换自定义CustomJEnv的使用,改用标准JNI API处理字符串转换:

// 新增字符串转换工具函数
std::string jniStringToStd(JNIEnv* env, jstring jstr) {
    if (jstr == nullptr) return "";
    const char* utfChars = env->GetStringUTFChars(jstr, nullptr);
    std::string result(utfChars);
    env->ReleaseStringUTFChars(jstr, utfChars);
    return result;
}

jboolean cppFunc::needTransform(JNIEnv *env, jobject instance, jstring classloader, jstring classname){
    std::string loaderStr = jniStringToStd(env, classloader);
    std::string classStr = jniStringToStd(env, classname);
    cppFunc::lastClass = loaderStr + "::" + classStr;
    return transformingClasses.count(cppFunc::lastClass) ? JNI_TRUE : JNI_FALSE;
}

2. 处理ClassLoader为null的边界情况

问题点

transform方法中的loader参数可能为null(Bootstrap类加载器加载的类),此时调用loader.getName()会抛出Java层空指针异常,若该异常被JNI层错误处理,或传递null的jstring到Native方法后未做检查,会触发JNI层空指针访问。

修复

在Java层提前处理loader为空的情况:

@Override
public byte[] transform(ClassLoader loader, String className, Class<?> classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer){
    String loaderName = loader == null ? "bootstrap" : loader.getName();
    if(nativeContent.INSTANCE.needTransform(loaderName, className)){
        System.out.println("[BML][INFO] Transforming " + loaderName + "::" + className);
        // ... 后续逻辑
    }
    return classfileBuffer;
}

3. 验证JNI方法注册的正确性

问题点

若JNI方法签名、类路径或方法名不匹配,JVM会无法找到正确的Native方法实现,调用时会触发崩溃。

修复

  1. 使用javah工具生成标准JNI头文件,对比现有签名:
    javah -classpath [你的类编译路径] gwy.bml.agent.nativeContent$cppFunc
    
  2. 修正JNI_OnLoad中类路径和注册逻辑,确保使用标准JNI API获取环境:
    JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *javaVm, void *reserved){
        jvm = javaVm;
        JNIEnv* env = nullptr;
        jint envResult = javaVm->GetEnv((void**)&env, JNI_VERSION_9);
        if (envResult != JNI_OK) return JNI_ERR;
    
        jclass targetClass = env->FindClass("gwy/bml/agent/nativeContent$cppFunc");
        if (targetClass == nullptr) return JNI_ERR;
    
        jint regResult = env->RegisterNatives(targetClass, methods, sizeof(methods)/sizeof(JNINativeMethod));
        if (regResult != JNI_OK) return JNI_ERR;
    
        // 后续文件操作逻辑...
        return JNI_VERSION_9;
    }
    

4. 确保DLL加载顺序与依赖完整性

问题点

若依赖DLL(如python311.dll)版本不匹配或加载失败,BML_T.dll会出现未定义行为,导致JVM崩溃。

修复

在Java静态代码块中增加加载日志与错误捕获:

static {
    for (String dll: dlls) {
        File dllFile = new File(dll);
        try {
            if(!dllFile.exists()) Files.copy(Objects.requireNonNull(agentMain.class.getResourceAsStream("/" + dll)), Path.of("./" + dll));
            System.load(dllFile.getAbsolutePath());
            System.out.println("[BML][INFO] 成功加载DLL: " + dll);
        } catch (IOException | UnsatisfiedLinkError e) {
            System.err.println("[BML][ERROR] 加载DLL失败: " + dll + ", 错误信息: " + e.getLocalizedMessage());
            e.printStackTrace();
            throw new RuntimeException("无法加载必要的DLL", e);
        }
    }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.14 00:09:49