使用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
相关产品推荐
相关产品推荐

