These functions return useful starting points to supply to mem_snapshot().

  • root_ns_registry() returns R's namespace registry as a list. It contains all the namespaces currently loaded in the R session.

  • root_cpp11() returns the precious list of cpp11. This is a doubly linked list preserved in R's own precious list.

  • root_precious_list() returns R's precious list. However this requires a custom build of R where R_PreciousList is exposed as a non-static symbol.

Usage,
root_cpp11()

root_ns_registry()

The precious list

The R precious list is (as currently implemented) a pairlist of objects currently protected via the C API function R_PreserveObject(). Preserved objects are stored in this pairlist until a corresponding R_ReleaseObject() call is performed. Some objects are meant to be preserved for the whole duration of the R session (global caches), others are preserved for a limited duration. It may happen that R_ReleaseObject() is not being called when it should. This causes a memory leak via the precious list.

R currently does not provide an easy way to get the precious list. So you will need to either patch R to expose it (e.g. remove its static qualifier) so that you can call root_precious_list(), or run R though a debugger like gdb or lldb.

If you choose to use a debugger, use p to print the address of the list:

p R_PreciousList
#> (SEXP) $0 = 0x000000010107cf58

Copy that address in an R string and dereference it with deref():

prec <- deref("0x000000010107cf58")

Avoid printing the precious list in the console because it contains a large amount of data, such as the global cache for the global environment and attached packages.

Some things to consider while working with the precious list:

  • If you record a snapshot of the precious list, beware that objects in the global environment will be reachable through the global cache. These objects are normally excluded from snapshots. You can exclude an object from the snapshot by stashing it with mem_stash().

  • If you take before and after snapshots, make sure to capture the R_PreciousList address each time. The precious list is currently implemented as a stack of pairlist nodes. If you don't refresh the pointer you will miss all new elements added on the top of the stack.