[Rd] R_PreserveObject, R_ReleaseObject : reference counting needed ?

Romain Francois romain.francois at dbmail.com
Sat Jan 2 22:43:14 CET 2010


On 01/02/2010 10:26 PM, Whit Armstrong wrote:
>
> Romain,
>
> Is the use of UNPROTECT_PTR discouraged?  I wonder why you haven't
> considered using it instead.

that's not what I said. It just felt not as easy to use as just grab a 
SEXP and say R_PreserveObject( x ) and then later R_ReleaseObject.

I did not mean to discourage people from using it. It is probably very 
stable indeed since it is used all over the place in the parser, and 
since the parser is probably the most used code in the R source tree, we 
would know if it did not work properly.

> I have a similar project that uses a ref counting scheme and handles
> the deletion of the shared object with UNPROTECT_PTR.  This method has
> been working fine, but if there are reasons I should not be using it,
> I would certainly like to know.
>
>> From memory.c: /* "unprotect_ptr" remove pointer from somewhere in R_PPStack */
>
> The code is very simple, it just walks backwards down the list until
> it hits your object.  Unless you are adding an obscene number of items
> to the protection stack in a given call, finding your object should be
> very fast.
>
> My example is here:
> http://github.com/armstrtw/rabstraction/blob/master/R.backend.hpp
 >
> template<SEXPTYPE RTYPE>
>    Rbackend<RTYPE>::~Rbackend() {
>      if(release_data_) {
>        if(R_object_!=R_NilValue) {
>          UNPROTECT_PTR(R_object_);
>        }
>      }
>    }

Thanks. I'll have a look.

> I still think all these Rcpp projects should come together some day.
> Dirk and I talked about combining about two years ago, but "real" work
> got it the way.  I'll ping you off list for a follow up.

Dirk is proving very cooperative and the "Rcpp" package is under a lot 
of changes currently in its new Rcpp namespace, while keeping the 
current interface.

Our main class is Rcpp::RObject that wraps any SEXP into a C++ object 
that basically R_PreserveObject when it is created, and R_ReleaseObject 
when the object is destroyed.

deriving from "RObject", we have "Environment" to deal specifically with 
environments (ENVSXP) , "Symbol" to deal with symbols (SYMSXP), 
"Language" for calls (LANGSXP) and the template XPTr for external 
pointers. The rest (vectors, functions, ...) will follow.

I'd suggest using the Rcpp mailing list for a follow up. 
https://lists.r-forge.r-project.org/cgi-bin/mailman/listinfo/rcpp-devel

> -Whit
>
>
> On Sat, Jan 2, 2010 at 12:24 PM, Romain Francois
> <romain.francois at dbmail.com>  wrote:
>> On 01/02/2010 06:01 PM, Simon Urbanek wrote:
>>>
>>>
>>> On Jan 2, 2010, at 5:07 AM, Romain Francois wrote:
>>>
>>>> Hello,
>>>>
>>>> We are currently making lots of changes to Rcpp (see the open Rcpp
>>>> mailing list if interested [1] in the details).
>>>>
>>>> We are now using [2] R_PreserveObject and R_ReleaseObject to manage
>>>> garbage collection instead of the PROTECT/UNPROTECT dance. This seems to
>>>> work well, but I was wondering if there was documentation about it.
>>>>
>>>
>>> I don't think so - the only documentation is the comment in the source.
>>
>>
>> Fair enough. FWIW, some mention of it in the R-ints or R-exts could be
>> valuable.
>>
>>
>>>> In particular, if we preserve the same SEXP twice (or more), should we
>>>> implement some sort of reference counting ?
>>>>
>>>
>>> Preserve/Release are for managing objects that are supposed to survive
>>> past the call and are not tied to any other R object. PROTECT/UNPROTECT are
>>> for temporary preservation within a call.
>>>
>>> Although you're right that Preserve/Release is effectively implemented as
>>> a stack at the moment it is not stated explicitly anywhere (this goes all
>>> the way back to R 0.64 so chances are that only Ross can comment..).
>>> However, for practical purposes it would be potentially dangerous to have it
>>> work like a flag because you can simply never know whether the same object
>>> was not already registered by some other code.
>>>
>>>
>>>> Reading the source (below, from memory.c) I think not, but some
>>>> confirmation would help.
>>>>
>>>> void R_PreserveObject(SEXP object)
>>>> {
>>>>     R_PreciousList = CONS(object, R_PreciousList);
>>>> }
>>>>
>>>> static SEXP RecursiveRelease(SEXP object, SEXP list)
>>>> {
>>>>     if (!isNull(list)) {
>>>>         if (object == CAR(list))
>>>>             return CDR(list);
>>>>         else
>>>>             CDR(list) = RecursiveRelease(object, CDR(list));
>>>>     }
>>>>     return list;
>>>> }
>>>>
>>>> void R_ReleaseObject(SEXP object)
>>>> {
>>>>     R_PreciousList =  RecursiveRelease(object, R_PreciousList);
>>>> }
>>>>
>>>>
>>>> I'd also be interested if there is some ideas on the relative efficiency
>>>> of the preserve/release mechanism compared to PROTECT/UNPROTECT.
>>>>
>>>
>>> PROTECT/UNPROTECT is more efficient because all it does is a pointer
>>> assignment -- Preserve has to allocate new node and fill it with all parts.
>>> On release the extra node is still floating in the GC pool etc.
>>>
>>> Normally there is not really a question of choice - within a call you want
>>> to use PROTET/UNPROTECT and for anything else you simply cannot use it so
>>> you have to use Preserve/Release. As a side note Preserve/Release is merely
>>> a convenience call, it is often more efficient to simply assign the object
>>> to another object you have control of (which is all Preserve really does).
>>>
>>> Cheers,
>>> Simon
>>
>> Thanks for this advice. This will make it easier to do the bookkeeping of
>> how many objects we preserve, etc ...
>>
>> Romain

-- 
Romain Francois
Professional R Enthusiast
+33(0) 6 28 91 30 30
http://romainfrancois.blog.free.fr
|- http://tr.im/IW9B : C++ exceptions at the R level
|- http://tr.im/IlMh : CPP package: exposing C++ objects
`- http://tr.im/HlX9 : new package : bibtex



More information about the R-devel mailing list