[Rd] Objects not gc'ed due to caching (?) in R's S3 dispatch mechanism

Winston Chang winstonchang1 at gmail.com
Tue Mar 27 05:49:33 CEST 2018


I'd like to emphasize that although Iñaki's example uses print(), it
also happens with other S3 generics. Please note that each of the
following examples might need to be run in a clean R session to work.

===========
Here's an example that doesn't use S3 dispatch. The finalizer runs correctly.

ident <- function(x) invisible(x)

env_with_finalizer <- function() {
  reg.finalizer(environment(), function(e) message("Finalizer called"))
  environment()
}

ident(env_with_finalizer())
gc() # Still in .Last.value
gc() # Finalizer called


===========
Here's an example that uses S3. In this case, the finalizer doesn't run.

ident <- function(x) UseMethod("ident")
ident.default <- function(x) invisible(x)

env_with_finalizer <- function() {
  reg.finalizer(environment(), function(e) message("Finalizer called"))
  environment()
}

ident(env_with_finalizer())
gc()
gc() # Nothing

However, if the S3 generic is called with another object, the
finalizer will run on the next GC:

ident(1)
gc() # Finalizer called

===========

This example is the same as the previous one, except that, at the end,
instead of calling the same S3 generic on a different object (that is,
ident(1)), it calls a _different_ S3 generic on a different object
(mean(1)).

ident <- function(x) UseMethod("ident")
ident.default <- function(x) invisible(x)

env_with_finalizer <- function() {
  reg.finalizer(environment(), function(e) message("Finalizer called"))
  environment()
}

ident(env_with_finalizer())
gc()
gc() # Nothing

# Call a different S3 generic
mean(1)
gc() # Finalizer called


-Winston

On Mon, Mar 26, 2018 at 4:46 PM, Iñaki Úcar <i.ucar86 at gmail.com> wrote:
> Hi,
>
> I initially opened an issue in the R6 repo because my issue was with
> an R6 object. But Winston (thanks!) further simplified my example, and
> it turns out that the issue (whether a feature or a bug is yet to be
> seen) had to do with S3 dispatching.
>
> The following example, by Winston, depicts the issue:
>
> print.foo <- function(x, ...) {
>   cat("print.foo called\n")
>   invisible(x)
> }
>
> new_foo <- function() {
>   e <- new.env()
>   reg.finalizer(e, function(e) message("Finalizer called"))
>   class(e) <- "foo"
>   e
> }
>
> new_foo()
> gc() # still in .Last.value
> gc() # nothing
>
> I would expect that the second call to gc() should free 'e', but it's
> not. However, if we call now *any* S3 method, then the object can be
> finally gc'ed:
>
> print(1)
> gc() # Finalizer called
>
> So the hypothesis is that there is some kind of caching (?) mechanism
> going on. Intended behaviour or not, this is something that was
> introduced between R 3.2.3 and 3.3.2 (the first succeeds; from the
> second on, the example fails as described above).
>
> Regards,
> Iñaki
>
> PS: Further discussion and examples in https://github.com/r-lib/R6/issues/140
>
> ______________________________________________
> R-devel at r-project.org mailing list
> https://stat.ethz.ch/mailman/listinfo/r-devel



More information about the R-devel mailing list