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

使用FFI在Rust与Java间传递数据时遇VM崩溃异常求助

Java调用Rust didcomm-rs库VM崩溃问题排查与修复

核心原因

VM崩溃的本质是Rust侧分配的内存未被正确释放:你的to_ptr函数通过mem::forget(cs)绕过了Rust的自动内存回收,但Java侧没有对应的释放逻辑,导致未回收的原生内存在JVM退出时触发崩溃检查。

关键问题点

  • mem::forget(cs)让Rust放弃对CString内存的所有权,这块内存成为“孤儿内存”,只能由外部手动释放
  • 前几次调用未崩溃是因为内存泄漏尚未触发JVM的临界检查,但最后一次调用后JVM退出,会扫描所有原生资源,未释放的内存触发崩溃

修复方案

1. Rust侧添加内存释放函数

给库新增一个对外暴露的函数,用来回收to_ptr返回的字符串指针:

use std::ffi::{CString, c_char};
use std::mem;

#[no_mangle]
pub extern "C" fn free_didcomm_string(ptr: *mut c_char) {
    unsafe {
        if !ptr.is_null() {
            // 将指针重新包装为CString,Rust会自动调用析构函数释放内存
            let _ = CString::from_raw(ptr);
        }
    }
}

2. Java侧强制释放内存

每次调用Rust获取字符串指针后,必须在使用完毕后调用释放函数,哪怕发生异常也要执行:

// JNI声明
public native long generateDidcommMessage();
public native void freeDidcommString(long ptr);

public String getDidcommMessage() {
    long ptr = generateDidcommMessage();
    try {
        // 通过JNI将原生指针转换为Java字符串
        return com.sun.jni.StringUTF.fromNative(ptr, true);
    } finally {
        // 确保内存一定会被释放
        freeDidcommString(ptr);
    }
}

调试技巧

  • 启用JVM原生内存追踪:添加JVM参数-XX:+PrintNativeMemoryTracking -XX:NativeMemoryTracking=detail,查看退出前的原生内存占用,确认是否有未释放的内存块
  • 用Valgrind检测泄漏:编译Rust库为release版本后,执行valgrind --leak-check=full java -jar 你的测试jar包,直接定位未释放的内存位置
  • 检查空指针场景:确保Rust返回的指针不会为空,释放函数中的空指针检查必须保留,避免空指针解引用崩溃

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.19 08:40:31