【问题标题】:How to stop memory leaks when using `as_ptr()`?使用 `as_ptr()` 时如何阻止内存泄漏?
【发布时间】:2015-09-14 00:00:45
【问题描述】:

由于这是我第一次学习系统编程,我很难理解规则。现在,我对内存泄漏感到困惑。让我们考虑一个例子。比如说,Rust 正在抛出一个 Python 将要捕获的指针(指向一个字符串)。

在 Rust 中,(我只是发送 CString 的指针)

use std::ffi::CString;

pub extern fn do_something() -> *const c_char {
    CString::new(some_string).unwrap().as_ptr()
}

在 Python 中,(我正在取消引用指针)

def call_rust():
    lib = ctypes.cdll.LoadLibrary(rustLib)
    lib.do_something.restype = ctypes.c_void_p
    c_pointer = lib.do_something()
    some_string = ctypes.c_char_p(c_pointer).value

现在,我的问题是关于释放内存。我认为它应该在 Python 中被释放,但是所有权突然出现。因为,as_ptr 似乎采用了不可变的引用。所以,我对是否应该在 Rust 或 Python (或两者都?)中释放内存感到困惑。如果是 Rust,那么当控制流回到 Python 时我应该如何释放它?

【问题讨论】:

  • 请注意,在这种情况下,没有内存泄漏。相反,它是一个释放后使用错误,通常更具破坏性。

标签: python memory-leaks rust ctypes ffi


【解决方案1】:

您的 Rust 函数 do_something 构造一个临时的 CString,将一个指针放入其中,然后删除 CString。 *const c_char 从您返回它的那一刻起就无效了。如果您在夜间使用,您可能需要CString#into_ptr 而不是CString#as_ptr,因为前者会消耗CString 而不会释放内存。在稳定版上,您可以mem::forget CString。然后你可以担心谁应该释放它。

从 Python 中解放出来将是棘手的或不可能的,因为 Rust 可能使用不同的分配器。最好的方法是公开一个 Rust 函数,它接受一个 c_char 指针,为该指针构造一个 CString(而不是将数据复制到新的分配中),然后删除它。不幸的是,中间部分(创建CString)目前在稳定版上似乎是不可能的:CString::from_ptr 是不稳定的。

一种解决方法是将整个CString 传递(指向)Python 并提供一个访问函数来从中获取char 指针。您只需将CString 装箱并将该框转换为原始指针。然后你可以有另一个函数将指针变回一个盒子并让它下降。

【讨论】:

  • CString 表示为Box<[u8]>; std::raw::Slice(不稳定)显示该类型的表示。如果您想转移所有权,来回转换可能是最好的方式。
  • @ChrisMorgan CString 变成了Box<[u8]>,同时我添加了into_ptr;在此之前,它是Vec<u8>。
  • @Shepmaster:我看到基于当前源代码而不是stable源代码来评论它是一个坏主意。或者更确切地说,变形是危险的。嗯,至少mem::transmute::<CString, *const [u8]>() 会因为大小不匹配而无法编译。
  • @Waffle'sCrazyPeanut 我很想听听如何使文档更清晰。重要的一点是 Rust 必须是释放 Rust 创建的任何东西的东西。
  • @Waffle'sCrazyPeanut 这取决于您的程序将运行多长时间以及该函数将被调用的频率。每次调用该函数时,都会泄漏内存(数量取决于字符串的长度)。如果你经常这样做(并且在足够长的时间内),你可能会耗尽内存(这会导致崩溃)。例如,这不是您希望在 Web 服务器中拥有的东西。
猜你喜欢
  • 2016-01-01
  • 2019-07-17
  • 1970-01-01
  • 1970-01-01
  • 2013-12-06
  • 1970-01-01
  • 1970-01-01
  • 2021-10-22
  • 1970-01-01
相关资源
最近更新 更多