Hi all,
We have recently started using the EmbedderHeapTracer APIs (upgrading to v8
6.2), and we've started to see some odd behavior. I was hoping someone
would be able to say what it is that's going on.
We have a C++ Wrapper class for hosted and marshaled objects. Internally
it stores two v8::Persistent<v8::Object> handles, both of which are weak,
with a registered finalizer callback. The first handle's finalizer
callback Reset()s the handle, and adds the Wrapper to a list of wrappers to
be deleted in the GC epilogue. The second handle's finalizer callback
ClearWeak()s the handle. When the GC epilogue happens, we walk the list of
wrappers to delete and call the Wrapper destructor. This destructor Reset()s
the second handle.
The v8::Object the Wrapper wraps has two embedder fields, with the second
one being a pointer to the Wrapper.
What we are seeing is that, infrequently (once in maybe 600,000 created
Wrapper objects), the following sequence of events occurs:
1. A Wrapper is created at address A
2. Several scavenge GCs occur, where we unconditionally mark all Wrappers
as active
3. Mark/Sweep GC prologue
1. Trace prologue
1. V8 informs us of an object with its second embedder field
pointing to address A
2. Trace epilogue
3. Weak finalizer callbacks are called for this object, we queue up
the Wrapper for deletion
4. Mark/Sweep GC epilogue
1. We delete the Wrapper
5. Mark/Sweep GC prologue
1. Trace prologue
1. V8 informs us of an object with its second embedder field
pointing to address A
At this point, the Wrapper at address A has been deleted, so we access
garbage memory.
We've looked into the GC code, and it seems that objects with weak
finalizer handles pointing at them are kept alive until the end of the
current GC cycle. Additionally our second weak handle which we make strong
until the destructor is called in the GC epilogue ensures that this is the
case. But in that GC cycle we clear out the last handle to this object on
our side, so we were under the impression that the object would no longer
be reachable. It seems as though somehow v8 is materializing a reference
to this object after we remove our final reference, causing it to be
retraced after we have deleted the associated Wrapper. Is there any reason
why v8 might be doing this?
As a work-around, we are now clearing the embedder fields in the first weak
finalizer callback where we add the object to the list of wrappers to
delete. This means that even if v8 decides to keep a reference, it will
not see it as a wrapper which should be traced, so we won't ever hear about
it again. But we'd like to understand what the root issue is so that we
can adjust our assumptions if necessary.
Thanks,
Daryl.
--
--
v8-users mailing list
[email protected]
http://groups.google.com/group/v8-users
---
You received this message because you are subscribed to the Google Groups
"v8-users" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
For more options, visit https://groups.google.com/d/optout.