Rust 如何在不释放缓冲区本身的情况下释放FFI缓冲区上分配的所有结构?

Rust 如何在不释放缓冲区本身的情况下释放FFI缓冲区上分配的所有结构?,rust,ffi,Rust,Ffi,我有一个Java程序,它通过JNA调用Rust,为Rust端提供一个指针,指向一个可能很大的(堆分配的)缓冲区,缓冲区中有连续排列的、以0结尾的UTF-8字符串。内存由Java端拥有,并在垃圾收集器完成关联对象时释放 我的目标是处理该缓冲区,将其解释为字符串向量,执行我需要执行的操作,并删除分配在缓冲区顶部的所有结构,例如Vec,strings等。由于缓冲区的潜在大小,我希望尽可能避免复制周围的数据 考虑以下代码: use std::ffi::CString; use std::os::raw:

我有一个Java程序,它通过JNA调用Rust,为Rust端提供一个指针,指向一个可能很大的(堆分配的)缓冲区,缓冲区中有连续排列的、以0结尾的UTF-8字符串。内存由Java端拥有,并在垃圾收集器完成关联对象时释放

我的目标是处理该缓冲区,将其解释为字符串向量,执行我需要执行的操作,并删除分配在缓冲区顶部的所有结构,例如
Vec
string
s等。由于缓冲区的潜在大小,我希望尽可能避免复制周围的数据

考虑以下代码:

use std::ffi::CString;
use std::os::raw::c_char;

pub extern "C" fn process_data(data: *const c_char, num_elements: i64) {
    let mut vec: Vec<String> = Vec::with_capacity(num_elements as usize);
    let mut offset = 0;

    unsafe {
        for _ in 0..num_elements {
            let ptr = { data.offset(offset as isize) };

            // Main goal here is to have no memory copy involved
            let s = String::from_utf8_unchecked(CString::from_raw(ptr as *mut c_char).into_bytes());

            offset += s.len() + 1; // Include string termination
            vec.push(s);
        }
    }

    // do stuff with the vector
    // ...

    // Now that we're done, vec would be dropped, freeing the strings, thus freeing their underlying memory.
}
然而,由于切片也是一个包含长度和指针的结构,通过执行上述操作,我认为我会泄漏此结构。我正在寻找使用该片并只返回类似
*const u8
的指针的内容


我有一种感觉,总的来说,我走的方向是正确的,但我错过了一些重要的东西,或者对锈病的了解太少,无法让它完全发挥作用。

重新阅读文档,重点是我的:

一个类型,表示“<强>拥有的<强> >,C兼容,NUL终止的字符串,中间没有NUL字节。

这种类型的目的是能够安全地从字节片或向量生成与C兼容的字符串

您不拥有这些字符串,Java拥有这些字符串。使用
&str
,而不是:

使用std::ffi::CStr;
使用std::os::raw::c_char;
pub extern“C”fn进程数据(数据:*常量C_char,num_元素:i64){
让mut-vec:vec=vec::具有_容量(num_元素用作usize);
不安全{
让mut ptr=数据;
对于0..num_元素中的u{
设s=CStr::from_ptr(ptr);
ptr=ptr.add(s.to_bytes().len()+1);//包括字符串终止
如果让Ok(s)=s.到_str(){
矢量推力;
}
}
}
}

当您的
Vec
被删除时,它只会删除引用,除了
Vec
本身之外,没有任何东西会被取消分配。

谢谢您,这完全有道理。我知道我错过了一些重要的事情:)
fn forget_vec(vec: Vec<String>) {
    vec.into_iter().map(|s| {
        Box::into_raw(s.into_bytes().into_boxed_slice());
    }
}
use std::ffi::CStr;
use std::os::raw::c_char;

pub extern "C" fn process_data(data: *const c_char, num_elements: i64) {
    let mut vec: Vec<&str> = Vec::with_capacity(num_elements as usize);

    unsafe {
        let mut ptr = data;

        for _ in 0..num_elements {
            let s = CStr::from_ptr(ptr);
            ptr = ptr.add(s.to_bytes().len() + 1); // Include string termination

            if let Ok(s) = s.to_str() {
                vec.push(s);
            }
        }
    }
}