也许 Rust 需要 "defer"

这篇文章主要讨论了在 Rust 中使用 FFI 时内存释放的问题,以及defer机制的相关情况。

  • 设置阶段:展示了一个简单的 Rust API,用于分配和返回动态分配的数组指针和长度,生成对应的 C 头文件后可以在 C 中使用。但代码存在一个微妙的错误,后续会继续探讨。
  • 首次尝试正确释放内存:在 Rust 测试中尝试像 C 一样使用libcfree函数来释放内存,测试通过但在 Miri 中会报错,因为 Rust 分配内存时调用的是libcmalloc,而释放内存需要libcfree,这导致了一些困惑,文档中对于直接free`Vec`指针的说法也存在矛盾。
  • 第二次尝试正确释放内存:尝试通过假装内存是由Box分配来解决问题,代码可以构建和测试通过,但在 Miri 中会报错,说明 Rust 在编译时和运行时看似正常,但在某些实验性分析器下会出现问题。
  • 第三次尝试正确释放内存:在代码库中定义了一个新的OwningArrayC结构体,用于携带Vec的容量信息,以正确释放内存,并添加了相应的函数。在 Rust 测试中使用该结构体后,Miri 不再报错。
  • Defer机制:使用scopeguard crate 的defer!宏来自动释放内存,但在测试中会出现编译错误,因为defer块持有独占的可变引用,其他代码无法使用该引用。
  • 可能的解决方案

    • 在语言中添加defer语句,并让 borrow checker 知道这个结构。
    • 小心手动释放内存,但难以扩展。
    • 使用类似goto的方法,但代码可读性差。
    • 通过重构代码使用句柄(数值 ID)来绕过 borrow checker。
    • 改进 borrow checker 而不添加defer
    • 使用 arena 来避免这些问题。
  • 结论:Rust + FFI 存在很多摩擦和问题,需要记住很多知识,容易出错,目前对于defer机制还在讨论中。同时还提到了一个关于Vec指针可能为 null 的问题,在 C 调用时需要进行防御性检查。

总的来说,在 Rust 中使用 FFI 进行内存管理比较复杂,需要注意很多细节,defer机制的实现也存在一些困难。

阅读 19
0 条评论