r - 当外部程序通过 R 的 C API 接口调用“Rf_allocXXX”时,谁在管理内存?
问题描述
我正在用 Rust 编写一个 R 包,它通过其 C API 接口与 R 通信。
一个对我来说似乎很棘手的基本问题是内存管理。
所以首先让我简要解释一下我的 Rust 程序是如何与 R 通信的。
首先,在 R 端,它使用.Call()
. 然后将 C 库链接到具有 C 兼容 ABI 的 Rust 静态库。
R 脚本正在做一些简单的工作,比如输入验证,并根据输入决定调用哪个 C 函数。然后 C 程序将调用传递给底层的 Rust 函数,这些函数作为 C 兼容函数公开。
到目前为止很清楚,一旦 Rust 完成计算并需要将结果发回,它就会变得棘手。
一种选择是直接调用Rf_allocXXX
Rust 端的函数,并将结果存储在其中。然后将 R 对象的原始指针传回 C,然后再传给 R。
但我不清楚这是否会导致内存泄漏。
在我看来,如果 Rust 调用Rf_allocXXX
,新的 R objected ( SEXP
) 是在 Rust 程序的堆内存上创建的。当传递原始指针时,Rust 不会破坏对象。但是接下来会发生什么?
请注意,SEXP
Rust 以这种方式创建的 直接传递回 C 和 R。没有重新分配。所以我似乎很不清楚这是否SEXP
会被 R 的 GC 正确释放。
一个相关的问题,
我从Rcpp
的源代码中注意到的是,它似乎只是调用 R 的 C API 来创建它的各种向量,它们是SEXP
.
但我还不清楚它如何处理内存管理。它只是简单地将SEXP
对象转回并且 R 将正确处理 GC 吗?
解决方案
这一切(一如既往)都在编写 R 扩展(而且始终不是最容易找到的......)
简而言之,当您调用 R 扩展包时,您基本上需要调用 R 的 API 及其Calloc()
和Free()
例程(和变体)。为什么?因为您返回给 R 的任何东西都会成为 R 对象,并且与所有其他 R 对象无法区分并且行为相同。包括非常重要的垃圾收集。
而做到这一点的唯一方法是通过 R 自己的分配器。所以 Rcpp 使用它。并创建实际上无法区分的对象。这使得一切正常。
R> Rcpp::cppFunction("IntegerVector foo() {
+ IntegerVector v = {1, 2, 3}; return v; }")
R> foo()
[1] 1 2 3
R> identical(foo(), c(1L, 2L, 3L))
[1] TRUE
R> identical(foo(), 1:3)
[1] TRUE
R>
但是作为第一步,你可以在 Rust 中做你自己的事情来计算结果,然后支付一次性转换成本(从你的对象到SEXP
R 期望作为 a 的结果.Call()
)。“在你跑之前先走”等等。Rust 绑定会很酷。我想你知道 Jeroen 和其他人已经做了一些工作吧?
推荐阅读
- javascript - 使用方法将对象添加到数组
- caffe - 如何在 caffe 中实现 soft-argmax?
- python - 使用 setup.py 运行目前需要 pipenv 的测试
- sql - 如何连接来自两个单独的 SQL 查询输出的行
- sql - 这两个查询都应该给我相同的结果 - SQL
- macos - 在 macOS 上安装 xv6
- html - 如何使导航对齐中心?
- python - Python Docker API 需要知道 attach(**kwargs) 到容器的语法
- javascript - 赛普拉斯:只运行一项测试
- reactjs - 这是 React 中使用 Hooks 的 2 路数据绑定的示例吗?