系统相关
首页 > 系统相关> > c – 在Rcpp函数内部替换Rcpp :: List的元素是否是内存安全的?

c – 在Rcpp函数内部替换Rcpp :: List的元素是否是内存安全的?

作者:互联网

我需要覆盖作为参数传递给Rcpp函数的Rcpp :: List对象的元素.我担心的是记忆安全.是否通过重新分配列表的非空元素,我实际上是重新布线指向原始内容的指针,但是从不解除分配存储原始内容的内存?如果是,如何解决这个问题?

我知道我可以很容易地修改一个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)
*/

当通过RStudio中的Rcpp获取时,print(l)命令输出以下内容

$a
[1] 4 5 6

这是期望的结果,所以我的问题仅涉及记忆安全.

解决方法:

A Rcpp::List是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
*/

这里使用更大的矢量来使效果更加突出.如果我现在使用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)

没有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)

所以在这两种情况下,valgrind都没有检测到任何内存泄漏.可达到的存储器的数量相差大约8×10 ^ 7字节,即原始矢量的大小为1美元.这表明R确实知道原始向量并在被告知这样做时释放它,但是当R自己决定运行垃圾收集器时也会发生这种情况.

标签:c,r,rcpp
来源: https://codeday.me/bug/20190827/1744736.html