Dear R .Call() insiders, Can someone enlighten me how to properly finalize external pointers in C code (R-2.5.1 win)? What is the relation between R_ClearExternalPtr and the finalizer set in R_RegisterCFinalizer?
I succeeded registering a finalizer that works when an R object containing an external pointer is garbage collected. However, I have some difficulties figuring out how to do that in an explicit closing function. I observed that - calling R_ClearExternalPtr does not trigger the finalizer and is dangerous because it removes the pointer before the finalizer needs it at garbage-collection-time (no finalization = memory leak) - calling the finalizer directly ensures finalization but now the finalizer is called twice (once again at garbage collection time, and I did not find documentation how to unregister the finalizer) - It works to delete the SEXP external pointer object but only if not calling R_ClearExternalPtr (but why then do we need it?) Furthermore it is unfortunate to delay freeing the external pointers memory if I know during runtime that it can be done immediately. Shouldn't R_ClearExternalPtr call the finalizer and then unregister it? (this would also work when removing the SEXP external pointer object is difficult because it was handed over to the closing function directly as a parameter) Best regards Jens Oehlschlägel // C-code static void rindex_finalize(SEXP extPtr){ pINT ptr = R_ExternalPtrAddr(extPtr); if(ptr){ Free(ptr); Rprintf("finalized\n"); }else{ Rprintf("nothing to finalize\n"); } return; } SEXP rindex_open( SEXP Sn ){ int i,n = INTEGER(Sn)[0]; pINT ptr = Calloc(sizeof(INT)*n, INT); SEXP extPtr, ret; for (i=0;i<n;i++){ ptr[i] = i; } extPtr = R_MakeExternalPtr(ptr, install("Rindex_extPtr"), R_NilValue); R_RegisterCFinalizer(extPtr, rindex_finalize); PROTECT(ret = allocVector(VECSXP, 1)); SET_VECTOR_ELT(ret,0,extPtr); UNPROTECT(1); return ret; } SEXP rindex_close( SEXP obj ){ int i, n= 10; SEXP ret, extPtr=VECTOR_ELT(obj, 0); pINT p, ptr = R_ExternalPtrAddr(extPtr); PROTECT(ret = allocVector(INTSXP, n)); p = INTEGER(ret); for (i=0;i<n;i++){ Rprintf("ptri=%d\n",ptr[i]); p[i] = ptr[i]; } /* this does finalize immediately but at next garbage collection again rindex_finalize(extPtr); */ /* this must not called otherwise the pointer is gone at garbage collection time R_ClearExternalPtr(extPtr); */ /* this triggers the finalizer but only at next garbage collection */ SET_VECTOR_ELT(obj,0,R_NilValue); UNPROTECT(1); return ret; } # R-Code initRindex <- function(){ dyn.load(file.path(.libPaths(), "rindex", "libs", paste("rindex", .Platform$dynlib.ext, sep = ""))) } doneRindex <- function(){ dyn.unload(file.path(.libPaths(), "rindex", "libs", paste("rindex", .Platform$dynlib.ext, sep = ""))) } openRindex <- function(n=10){ .Call("rindex_open", as.integer(n)) } closeRindex <- function(extPtr){ .Call("rindex_close", extPtr) } if (FALSE){ # now try it require(rindex) initRindex() extPtr <- openRindex() extPtr extPtr2 <- closeRindex(extPtr) extPtr2 gc() extPtr <- openRindex() extPtr2 <- extPtr extPtr2 rm(extPtr) gc() extPtr2 rm(extPtr2) gc() extPtr2 doneRindex() } > version _ platform i386-pc-mingw32 arch i386 os mingw32 system i386, mingw32 status major 2 minor 5.1 year 2007 month 06 day 27 svn rev 42083 language R version.string R version 2.5.1 (2007-06-27) -- Psssst! Schon vom neuen GMX MultiMessenger gehört? Der kanns mit allen: http://www.gmx.net/de/go/multimessenger ______________________________________________ R-help@stat.math.ethz.ch mailing list https://stat.ethz.ch/mailman/listinfo/r-help PLEASE do read the posting guide http://www.R-project.org/posting-guide.html and provide commented, minimal, self-contained, reproducible code.