Question

This is a follow up to a previous question here on storing and retrieving matrices in memory using xptr - which was fantastically answered - thank you very much. Now that I can create and retrieve matrices in memory using xptr how do I properly finalize/destroy the object. Rcpp objects should be automatically garbage collected on deletion but when I create the pointer, if I delete it in R I have to run gc() twice to recover the memory e.g.

// This function wraps the matrix an returns a pointer
// [[Rcpp::export]]
SEXP writeMemObject(NumericMatrix mat)
{
  XPtr<NumericMatrix> ptr(new NumericMatrix(mat), true);
  return ptr;
}

The function to retrieve the matrix (from previous answer)

// [[Rcpp::export]]
NumericMatrix getMemObject(SEXP ptr)
{
  XPtr<NumericMatrix> out(ptr);
  return *out;
}

Then in R

createMemMatrix <- function(dims){
  ptr <- writeMemObject(matrix(runif(prod(dims)), nc = dims[2]))
  return(ptr)
}

ptr <- createMemMatrix(c(1e4, 1e4))
#mat <- getMemObject(ptr) # this works but not run here
rm(ptr);
gc(); # nothing seems to happen in memory
gc(); # memory is freed (visible in system monitor)

The bigmemory R package was mentioned in the answer to the previous question and their objects are memory freed right away

# In R
require(bigmemory)
# be careful this is a large matrix
x1 <- big.matrix(ncol = 1e4, nrow = 1e4)
x1[,] <- runif(1e8)
rm(x1)
gc() # memory is freed right away (visible on system monitor)

I have tried a similar method used in the bigmemory package and I to register the pointer when I create it:

// C function for destroying the matrix behind the pointer
void destroyItem(SEXP ptr)
{
  NumericMatrix *pm=(NumericMatrix*)(R_ExternalPtrAddr(ptr));
  delete pm;
  R_ClearExternalPtr(ptr);
}

// This function wraps the matrix an returns a pointer
// [[Rcpp::export]]
SEXP writeMemObject(NumericMatrix mat)
{
  XPtr<NumericMatrix> ptr(new NumericMatrix(mat), true);
  R_RegisterCFinalizerEx(ptr, (R_CFinalizer_t) destroyItem, (Rboolean) TRUE);
  return ptr;
}

But this does not make a difference. The bigmemory package is great but I think it is worth doing this using Rcpp objects because a wide range of objects can be stored in memory.

Was it helpful?

Solution

R has a generational garbage collector, see for example this section of R internals. So calling gc() might not trigger a full collection every time.

Also, please note that XPtr already registers a finalizer that calls delete, so you don't need to register the destryItem finalizer. You only need to register a finalizer to do something in addition to deleteing the pointer. Luckily you don't get a double delete thanks to your R_ClearExternalPtr but this is dangerous anyway.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top