[Rprotobuf-yada] finalizer for messages

Romain Francois romain.francois at dbmail.com
Wed Dec 16 18:15:11 CET 2009


On 12/16/2009 06:05 PM, Dirk Eddelbuettel wrote:
> On 16 December 2009 at 17:26, Romain Francois wrote:
> | I think the problem is now solved, and we have a cleaner package that
> | plays well (at least I think) with R's garbage collector.
> |
> |>  require( RProtoBuf )
> | Loading required package: RProtoBuf
> | Loading required package: Rcpp
> |>  message<- new( tutorial.Person, id = 1 )
> |>  message<- new( tutorial.Person, id = 1 )
> |>  message<- new( tutorial.Person, id = 1 )
> |>  message<- new( tutorial.Person, id = 1 )
> |>  gc()
> | RProtoBuf finalizing Message (0x9258f68)
> | RProtoBuf finalizing Message (0x91ce378)
> | RProtoBuf finalizing Message (0x97f27b0)
> |           used (Mb) gc trigger (Mb) max used (Mb)
> | Ncells 260797  7.0     407500 10.9   350000  9.4
> | Vcells 210014  1.7     786432  6.0   500691  3.9
> |
> | previously the 3 first messages did not free their memory after the
> | external pointer was GC'd.
> |
> | I'll leave debugging messages as above for some time.
>
> I had to look at that for second .... so we get three finalizers / cleanups
> because out of four allocations, only one is reachable?

yep. same if you do things like :

f <- function( ){
	message <- new( tutorial.Person )
	rnorm( 10 )
}
f()

the message is now subject for garbage collection, ...

 > gc()
RProtoBuf finalizing Message (0x96b5518)

> Nifty, my friend, very nifty!
>
> Dirk

I had lots of "TODO: finalizers" in the code since the project started, 
and could not really sleep knowing of all this lost memory.

It is all actually very easy to do with external pointers, even if the 
manual is a bit harsh at first.

SEXP ptr = PROTECT( R_MakeExternalPtr( (void*)p ,
	R_NilValue, R_NilValue));

The first argument is the pointer the external pointer wraps. The two 
other arguments are things we also want to protect from garbage collection.

Then, we do :

R_RegisterCFinalizerEx( ptr, Message_finalizer , _FALSE_ ) ;

to register a finalizer with the external pointer, meaning when R 
garbage collects the external pointer, it calls the function 
Message_finalizer with the external pointer as its argument :

void Message_finalizer( SEXP xp){
	if (TYPEOF(xp)==EXTPTRSXP) {
		GPB::Message* message = (GPB::Message*)XPP(xp) ;
		FIN_DBG( message, "Message" ) ;
		delete message;
	}
}

The FIN_DBG macro just prints the message using Rprintf, which will 
disappear at some point.



-- 
Romain Francois
Professional R Enthusiast
+33(0) 6 28 91 30 30
http://romainfrancois.blog.free.fr
|- http://tr.im/HlX9 : new package : bibtex
|- http://tr.im/Gq7i : ohloh
`- http://tr.im/FtUu : new package : highlight



More information about the Rprotobuf-yada mailing list