我需要覆盖Rcpp::List作为参数传递给Rcpp函数的对象的元素。我关心的是内存安全性。是通过重新分配列表的非空元素来有效地重新链接指向原始内容的指针,却从未取消分配存储原始内容的内存的情况吗?如果是的话,如何解决呢?
我知道我可以轻松地修改作为元素的Rcpp对象(例如Rcpp::NumericVector)Rcpp::List,因为它Rcpp::NumericVector会进行浅拷贝。但是,这不能满足我的要求,即用其他东西完全替换元素。
下面,我包括一个C ++代码段,该段显示了我所引用的场景。
#include <Rcpp.h>
using namespace Rcpp;
// [[Rcpp::export]]
void replaceListElement(List l)
{
std::vector<int> v;
v.push_back(4);
v.push_back(5);
v.push_back(6);
l["a"] = v;
}
/*** R
l <- list()
l$a <- c(1,2,3)
replaceListElement(l)
print(l)
*/
Run Code Online (Sandbox Code Playgroud)
当通过RStudio中的Rcpp来源时,该print(l)命令输出以下内容
$a
[1] 4 5 6
Run Code Online (Sandbox Code Playgroud)
这是理想的结果,所以我的问题仅与内存安全有关。
A Rcpp::List是a Vector<VECSXP>,即指向其他向量的指针的向量。如果将新的向量分配给此列表中的某个元素,则实际上只是在更改指针而没有释放指针过去指向的内存。但是,R仍然知道此内存,并通过其垃圾回收器将其释放。我们可以通过一个简单的实验看到这一点,在该实验中,我使用了C ++代码,但R代码略有变化:
#include <Rcpp.h>
using namespace Rcpp;
// [[Rcpp::export]]
void replaceListElement(List l)
{
std::vector<int> v;
v.push_back(4);
v.push_back(5);
v.push_back(6);
l["a"] = v;
}
/*** R
l <- list()
l$a <- runif(1e7)
replaceListElement(l)
print(l)
gc() # optional
*/
Run Code Online (Sandbox Code Playgroud)
在这里,使用更大的向量使效果更加突出。如果我现在使用R -d valgrind -e 'Rcpp::sourceCpp("<filename>")'该gc()电话,则得到以下结果
==13827==
==13827== HEAP SUMMARY:
==13827== in use at exit: 48,125,775 bytes in 9,425 blocks
==13827== total heap usage: 34,139 allocs, 24,714 frees, 173,261,724 bytes allocated
==13827==
==13827== LEAK SUMMARY:
==13827== definitely lost: 0 bytes in 0 blocks
==13827== indirectly lost: 0 bytes in 0 blocks
==13827== possibly lost: 0 bytes in 0 blocks
==13827== still reachable: 48,125,775 bytes in 9,425 blocks
==13827== of which reachable via heuristic:
==13827== newarray : 4,264 bytes in 1 blocks
==13827== suppressed: 0 bytes in 0 blocks
==13827== Rerun with --leak-check=full to see details of leaked memory
==13827==
==13827== For counts of detected and suppressed errors, rerun with: -v
==13827== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
Run Code Online (Sandbox Code Playgroud)
而且没有gc()电话:
==13761==
==13761== HEAP SUMMARY:
==13761== in use at exit: 132,713,314 bytes in 10,009 blocks
==13761== total heap usage: 34,086 allocs, 24,077 frees, 173,212,886 bytes allocated
==13761==
==13761== LEAK SUMMARY:
==13761== definitely lost: 0 bytes in 0 blocks
==13761== indirectly lost: 0 bytes in 0 blocks
==13761== possibly lost: 0 bytes in 0 blocks
==13761== still reachable: 132,713,314 bytes in 10,009 blocks
==13761== of which reachable via heuristic:
==13761== newarray : 4,264 bytes in 1 blocks
==13761== suppressed: 0 bytes in 0 blocks
==13761== Rerun with --leak-check=full to see details of leaked memory
==13761==
==13761== For counts of detected and suppressed errors, rerun with: -v
==13761== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
Run Code Online (Sandbox Code Playgroud)
因此,在两种情况下valgrind都不会检测到任何内存泄漏。仍可访问的内存量相差约8x10 ^ 7字节,即中的原始向量的大小l$a。这表明R确实知道原始向量,并在被告知这样做时将其释放,但是当R自行决定运行垃圾收集器时,也会发生这种情况。