< 返回版块

eweca-d 发表于 2022-03-13 23:26

想通过cdylib使用rust函数,返回Vec<Vec<[f64;2]>>到python里,最外层固定是4个大小。因为Vec套着Vec套着Array,想着用struct,实现如下:

#[repr(C)]
pub struct DataBase {
    a: Data,
    b: Data,
    c: Data,
    d: Data,
}

impl DataBase {
    fn new(mut data: Vec<Data>) -> Self {
        let d = data.pop().unwrap();
        let c = data.pop().unwrap();
        let b = data.pop().unwrap();
        let a = data.pop().unwrap();
        Self {a, b, c, d}
    }
}

#[repr(C)]
pub struct Data {
    pair: *mut Pair,
    pair_num: i32,
    pair_capacity: i32,
}

impl Data {
    fn new(mut pairs: Vec<Pair>) -> Self {
        let pair = pairs.as_mut_ptr();
        let pair_num = pairs.len() as i32;
        let pair_capacity = pairs.capacity() as i32;
        mem::forget(pairs);
        Self { pair, pair_num, pair_capacity }
    }
}

#[repr(C)]
pub struct Pair {
    pair0: f64,
    pair1: f64,
}

impl Pair {
    fn new(pair0: f64, pair1: f64) -> Self {
        Self { pair0, pair1 }
    }
}

impl From<Vec<Vec<[f64; 2]>>> for DataBase {
    fn from(raw_database: Vec<Vec<[f64; 2]>>) -> Self {
        let mut database = vec![];
        for data in raw_database.iter() {
            let mut foo_pairs = vec![];
            for pair in data.iter() {
                foo_pairs.push(Pair::new(pair[0], pair[1]));
            }
            database.push(Data::new(foo_pairs));
        }

        Self::new(database)
    }
}

#[no_mangle]
pub extern "C" fn generate_data(x: f64) -> *mut DataBase {
    let ret: Vec<Vec<[f64; 2]>> = pre_lib::generate_data(x).unwrap();
    let mut database = DataBase::from(ret);
    println!("arr len 0 = {}, arr len 1= {}", database.a.pair_num, database.c.pair_num);
    let ret: *mut DataBase = &mut database;
    mem::forget(database);
    ret
}

发现一个奇怪的问题,就是不用println!这句,貌似DataBase占据的内存就被释放了,数据就被清空了,但是我明明使用了mem::forget。而当我调试的时候意外加入了这个println!结果它就正常了。

另外求教下,这个*mut DataBase传回来之后怎么销毁啊,直接进入fn free_database(_database: *mut DataBase) -> ()可以就销毁了么?还是说需要重做*mut PairVec<Pair>

评论区

写评论
作者 eweca-d 2022-03-14 11:12

写错了,修订一下:

#[no_mangle]
pub extern "C" fn free_generate_data_files(ptr: *mut DataBase) {
    unsafe {
        if ptr.is_null() {
            return;
        }
        let database = Box::from_raw(ptr);
        let _foo = Vec::from_raw_parts(database.a.pair, database.a.pair_num as usize, database.a.pair_capacity as usize);
        let _foo2 = Vec::from_raw_parts(database.b.pair, database.b.pair_num as usize, database.b.pair_capacity as usize);
        let _foo3 = Vec::from_raw_parts(database.c.pair, database.c.pair_num as usize, database.c.pair_capacity as usize);
        let _foo4 = Vec::from_raw_parts(database.d.pair, database.d.pair_num as usize, database.d.pair_capacity as usize);
    }
}

难怪感觉稍微有点内存泄露,这下正确的使用了Box::from_raw之后,没有任何泄露问题了。

--
👇
Grobycn: DataBase 是在栈上分配的,后面的程序会可能覆盖这一部分内存,相当于丢失了指向底层数据的指针。 看看下面的程序,可以看到底层的浮点数数据还在,但是 DataBase 已经被回收了。 可以考虑用 Box::leakBox::from_raw

playground

作者 eweca-d 2022-03-14 11:04

感谢大佬,成功了。类似这样:

    let database = Box::new(DataBase::from(ret));
    let ret: *mut DataBase = Box::leak(database) as *mut DataBase;

释放的时候类似这样:

#[no_mangle]
pub extern "C" fn free_generate_data(ptr: *mut DataBase) {
    unsafe {
        if ptr.is_null() {
            return;
        }
        let database = Box::from(ptr);
        let foo = Vec::from_raw_parts((**database).a.pair, (**database).a.pair_num as usize, (**database).a.pair_capacity as usize);
        let foo2 = Vec::from_raw_parts((**database).b.pair, (**database).b.pair_num as usize, (**database).b.pair_capacity as usize);
        let foo3 = Vec::from_raw_parts((**database).c.pair, (**database).c.pair_num as usize, (**database).c.pair_capacity as usize);
        let foo4 = Vec::from_raw_parts((**database).d.pair, (**database).d.pair_num as usize, (**database).d.pair_capacity as usize);
    }
}

目前运行良好,也没有啥特别明显的内存泄露问题了。

感谢!

--
👇
Grobycn: DataBase 是在栈上分配的,后面的程序会可能覆盖这一部分内存,相当于丢失了指向底层数据的指针。 看看下面的程序,可以看到底层的浮点数数据还在,但是 DataBase 已经被回收了。 可以考虑用 Box::leakBox::from_raw

playground

Grobycn 2022-03-14 00:44

DataBase 是在栈上分配的,后面的程序会可能覆盖这一部分内存,相当于丢失了指向底层数据的指针。 看看下面的程序,可以看到底层的浮点数数据还在,但是 DataBase 已经被回收了。 可以考虑用 Box::leakBox::from_raw

playground

1 共 3 条评论, 1 页