v8 SetWeak callback is not called after context disposal

551 views
Skip to first unread message

Sergey F.

unread,
Jan 8, 2016, 1:59:29 PM1/8/16
to v8-users
I have v8 integration which allocates some objects on c++ side, wraps them and makes available to js code
Everything works perfect, when object becomes unreachable v8 GC calls SetWeak callback and I'm able to free c++ allocated memory

But when I do context disposal(via calling persistent handle .Reset() method) why the remaining SetWeak callbacks aren't being triggered by v8? 
Should I do this cleanup manually?

Thanks!

Ben Noordhuis

unread,
Jan 9, 2016, 7:47:31 AM1/9/16
to v8-u...@googlegroups.com
Weak callbacks are not guaranteed to run, so yes, you need to clean up manually.

If your persistent handles have a class id, you can iterate over them
with v8::Isolate::VisitHandlesWithClassIds() before disposing the
isolate.

For per-context cleanup, you'll have to devise something else. You
could assign per-context class ids and filter on them but that may not
be very efficient when there are many contexts.

Sergey F.

unread,
Jan 9, 2016, 8:15:43 AM1/9/16
to v8-u...@googlegroups.com
Thanks very much for the answer, Ben!

Hm... looks like there is some other problem with my v8 usage, I just made a quick check:
- made huge allocation of memory within the context(around 1 gb)
- do some work
- call .Reset() on all persistent handles and manually remove c++ allocated memory
- memory allocated by context aren't being freed by V8

I just somehow thought it would be totally reasonable to expect v8 to call my SetWeak callbacks when the context(and all dedicated objects within their c++ counterparts) are being disposed
As far as I know V8 must dispose all context-allocated memory when I'm calling Reset on context persistent handle(no other references to it)
Looks like I'm missing something fundamental

What is the proper way to dispose V8 context and free all js-allocated resources that belong to this particular context?

Thanks again!


--
--
v8-users mailing list
v8-u...@googlegroups.com
http://groups.google.com/group/v8-users
---
You received this message because you are subscribed to a topic in the Google Groups "v8-users" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/v8-users/z3bVyJRyCf4/unsubscribe.
To unsubscribe from this group and all its topics, send an email to v8-users+u...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Sergey F.

unread,
Jan 9, 2016, 8:34:55 AM1/9/16
to v8-u...@googlegroups.com
Also one note, I do not wish to dispose the whole isolate
I would like to dispose the context only
My usage pattern:
- create fixed pool of isolates(= cores count)
- allocate/dispose contexts to execute user-defined code

Sergey F.

unread,
Jan 9, 2016, 8:37:17 AM1/9/16
to v8-u...@googlegroups.com
From my tests V8 disposes memory only when I'm calling isolate->Dispose()
Is it ever possible to dispose memory on per context basis?

Sergey F.

unread,
Jan 9, 2016, 9:23:04 AM1/9/16
to v8-u...@googlegroups.com
I also creates SO question regarding v8 behavior with some code attached, please see: 

Ben Noordhuis

unread,
Jan 9, 2016, 9:47:55 AM1/9/16
to v8-u...@googlegroups.com
On Sat, Jan 9, 2016 at 3:23 PM, Sergey F. <let...@gmail.com> wrote:
> I also creates SO question regarding v8 behavior with some code attached,
> please see:
> http://stackoverflow.com/questions/34694591/v8-impossible-to-free-memory-allocated-by-context

Reproducing your example here for posterity:

Isolate::CreateParams create_params;
create_params.array_buffer_allocator = &array_buffer_allocator;

Isolate* isolate = Isolate::New(create_params);
Locker locker(isolate);
Isolate::Scope isolate_scope(isolate);
HandleScope handle_scope(isolate);

Local<Context> ctx = Context::New(isolate);
Context::Scope context_scope(ctx);

Local<Script> script;
Local<String> name = String::NewFromUtf8(isolate, "wtf.js");
Local<String> source = String::NewFromUtf8(isolate, "var a = [];
for(var i = 0; i < 300; i++) a.push(new Array(1000000).join('*'));");
ScriptOrigin origin(String::NewFromUtf8(isolate, "wtf.js"));

script = Script::Compile(ctx, source, &origin).ToLocalChecked();
Handle<Value> result = script->Run(ctx).ToLocalChecked();

The first thing that stands out to me is that |ctx| is scoped to the
lifetime of |handle_scope|, i.e., |ctx| won't be eligible for garbage
collection until |handle_scope| goes out of scope.

Sergey F.

unread,
Jan 9, 2016, 9:51:04 AM1/9/16
to v8-u...@googlegroups.com
I call this inside a c++ function, so it definitely goes out of the scope with the whole handle_scope...
but memory isn't being freed

Ben Noordhuis

unread,
Jan 9, 2016, 9:58:53 AM1/9/16
to v8-u...@googlegroups.com
On Sat, Jan 9, 2016 at 3:51 PM, Sergey F. <let...@gmail.com> wrote:
> I call this inside a c++ function, so it definitely goes out of the scope
> with the whole handle_scope...
> but memory isn't being freed

Are you retaining a reference to the script or the result or anything
else from the context? Contexts are all-or-nothing affairs; if you
retain a reference to something inside a context, you retain it whole
(with primitives like strings and booleans being the exception.)

You can try calling v8::Isolate::ContextDisposedNotification() when
you are sure the context is well and truly dead. I have had mixed
results with that myself so don't expect miracles.

Sergey F.

unread,
Jan 9, 2016, 10:14:17 AM1/9/16
to v8-u...@googlegroups.com
Hm, it seems I've found something
Context handle got out of visibility and thus is eligible for GC, but GC is not triggering as it seems to be enough memory(from V8 point of view)

Calling isolate->RequestGarbageCollectionForTesting(Isolate::kFullGarbageCollection); triggers context garbage collection

Pavel Medvedev

unread,
Jan 9, 2016, 10:54:05 AM1/9/16
to v8-users
Hi Sergey,


On Saturday, January 9, 2016 at 6:14:17 PM UTC+3, Sergey F. wrote:
Hm, it seems I've found something
Context handle got out of visibility and thus is eligible for GC, but GC is not triggering as it seems to be enough memory(from V8 point of view)

Calling isolate->RequestGarbageCollectionForTesting(Isolate::kFullGarbageCollection); triggers context garbage collection



You mentioned about large amount of memory allocation on C++ side. There is a v8::Isolate::AdjustAmountOfExternalAllocatedMemory() function to
notify GC in V8 about such memory allocations. Maybe it would help.

Sergey F.

unread,
Jan 9, 2016, 11:01:40 AM1/9/16
to v8-u...@googlegroups.com
Hi Pavel!
Already using this thing to give v8 an estimate of external memory it indeed helps to call GC during the JS life cycle
But the thing that V8 does not call weak callbacks when context is being garbage collected is still kind of mystery for me(imo it's wrong)

--

Jochen Eisinger

unread,
Jan 11, 2016, 3:49:06 AM1/11/16
to v8-u...@googlegroups.com
Garbage collection is not necessarily triggered immediately when you dispose a context. If you rely on freeing the C++ memory right when the context goes out of scope, you can't rely on the GC to trigger at this very moment.

best
-jochen

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 v8-users+u...@googlegroups.com.
Reply all
Reply to author
Forward
0 new messages