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
не обнаруживает утечки памяти.Объем все еще достижимой памяти отличается примерно на 8x10 ^ 7 байт, то есть размер исходного вектора в l$a
.Это демонстрирует, что R действительно знает об исходном векторе и освобождает его, когда ему говорят об этом, но это также происходит, когда R сам решает запустить сборщик мусора.