4

After answering about tracemem recently, I learned about retracemem. The help for ?retracemem and the example therein leave me unenlightened.

What does retracemem actually do and why? It doesn't do what I thought it would do, i.e. point one object to the memory location of another, at least as far as I can tell.

I tried a wizardly invocation like .Internal(inspect()), which performs no magic for me:

> a = 1:10
> b = a[-1]
> .Internal(inspect(a))
@00000000087AE578 13 INTSXP g0c4 [NAM(2)] (len=10, tl=23336) 1,2,3,4,5,...
> .Internal(inspect(b))
@00000000087AE8E8 13 INTSXP g0c4 [NAM(2)] (len=9, tl=7208) 2,3,4,5,6,...
> retracemem(b,retracemem(a))
> .Internal(inspect(b))
@00000000087AE8E8 13 INTSXP g0c4 [NAM(2)] (len=9, tl=7208) 2,3,4,5,6,...
Community
  • 1
  • 1
Iterator
  • 20,250
  • 12
  • 75
  • 111

1 Answers1

1

I think retracemem() just lets you tag a variable copy, which wouldn't produce a tracemem statement (such as a b above which is really just a copy of a sans the first element), as being derived from the same source variable, so you can continue to watch the copies/partial copies propagate and see that they derive from the same source.

For example, how does A's memory get copied/propagated:

> A <- 1:10
> tracemem(A)
[1] "<0x100a2a978>"
> B <- A                                # Assignment to B doesn't make copy
> C <- A + 1                            # Assignment to C makes copy, alters it
tracemem[0x100a2a978 -> 0x1020ebbf0]: 
> D <- C + 1                            # Assignment to D makes copy, alters it
tracemem[0x1020ebbf0 -> 0x1020ebc98]: 
> E <- B + 1                            # Assignment to E makes copy, alters it
tracemem[0x100a2a978 -> 0x1020a4208]: 
> F <- A[-1]                            # Assignment to F doesn't make copy?
> G <- F + 1                            # Even after altering it?
> retracemem(F, retracemem(A))          # Hint to R that F is really A derived
tracemem[<0x100a2a978> -> 0x1009c5910]: 
> G <- F + 1                            # Reassignment to G makes copy, alters it
tracemem[0x1009c5910 -> 0x1020a4748]: 

But then again, I could be entirely wrong...

Zach
  • 2,445
  • 3
  • 20
  • 25
  • I must be dense. One interpretation I have is that the fact no message is printed when G is assigned indicates that F's assignment destroys the trace. Later, both `tracemem` or `retracemem` seem to me to give the same subsequent behavior when doing the second G assignment. In that case, it looks like they're the same. I'm not sure how we can benefit from `retracemem` in this scenario. There must be something I'm missing. – Iterator Sep 07 '11 at 15:14
  • I had a look at the source for `do_tracemem()` and `do_retracemem()`. There doesn't seem to be much difference between them. `do_retracemem()` marks the new object to be traced (the same way `do_tracemem()` does), then spits out a line showing the link between the new object and the previous, then prints out what I'm assuming is a listing of the function calls on the stack (you don't see this unless you've called `retracemem()` inside a function call). I think it's just a bridge for when you want to link the memory usage origins under iffy circumstances. – Zach Sep 07 '11 at 16:40
  • I also looked at the code (in `debug.c`, right?), and came to a similar conclusion. I love it when code is undocumented and uncommented. Though this little comment was interesting: `/* FIXME: ...` - it's a harmless issue, I think, but it was initially eye-catching. Thanks for taking the time to look at this & for the insights. – Iterator Sep 08 '11 at 12:12
  • 2022: I get different answers from running the code above. – pglpm Oct 22 '22 at 11:55