Garbage Collection on Dispose() of Context

151 views
Skip to first unread message

Abdulla

unread,
Nov 29, 2009, 6:45:28 PM11/29/09
to v8-users
According to the ChangeLog for version 1.0.3, garbage collection is
forced when disposing contexts, but I can't seem to trigger it in
order to destroy weak references. Am I doing something wrong?

Xiang

unread,
Nov 29, 2009, 11:49:16 PM11/29/09
to v8-users
Hi, Abdulla,

GC will be triggered when a new context is created(You can find it
when you try to trace Context::New()).

It used some heuristic method for better performance.


Cheers~
Xiang

Abdulla Kamar

unread,
Nov 30, 2009, 1:16:35 AM11/30/09
to v8-u...@googlegroups.com
Hi Xiang

I've tried that, but it still doesn't destroy the weak references.




--
Thank you
Abdulla

Xiang

unread,
Nov 30, 2009, 2:39:43 AM11/30/09
to v8-users
Hi, Abdulla,


To make sure your weak handle callback is called, you have to create
lots of objects. As GC will only clean necessary space based on its
heuristic rules, not all garbages.

You can use API SetResourceConstraints() to constraint the heap
resource . It will make it easier to trigger GC(there is a test case
in cctest).

There is a also sample about weak handle callback in
http://groups.google.com/group/v8-users/browse_thread/thread/9effc94911772167/f4806a7e28d6c9f7?lnk=gst&q=Jacob#f4806a7e28d6c9f7

You will find it useful.


Cheers~
Xiang

Abdulla Kamar

unread,
Nov 30, 2009, 3:17:06 AM11/30/09
to v8-u...@googlegroups.com
Hi Xiang

I've had a look through that thread before. I'll try SetResourceConstraints(), but that seems like a hack to me, especially since I can't change it after the VM has been initialised. What I really need is a way to destroy all weak references when I've disposed the context.

Xiang Zhong

unread,
Nov 30, 2009, 4:41:42 AM11/30/09
to v8-users
Hi, Abdulla,


Currently, v8 can't do that for you. v8 can't guarantee all your destrutors be called even when you exit the program.
If you want that, you have to manage the heap resource yourself.

v8 do that because GC is very expensive operation and v8 don't want to slowdown chrome when closing a tab.


There are plenty of discussion about GC before.

Abdulla Kamar

unread,
Nov 30, 2009, 6:17:22 AM11/30/09
to v8-u...@googlegroups.com
Hi Xiang

I've read the discussion, however there was explicit mention of it in the ChangeLog, hence my inquiry.

It's something I would think to be important and useful. I also have Lua bindings for my code, and it can guarantee cleanup when I destroy the interpreter's state.

Stephan Beal

unread,
Nov 30, 2009, 10:30:47 AM11/30/09
to v8-u...@googlegroups.com
On Mon, Nov 30, 2009 at 12:17 PM, Abdulla Kamar <abdull...@gmail.com> wrote:
I've read the discussion, however there was explicit mention of it in the ChangeLog, hence my inquiry.

Hi, Abdulla!

This is a _sorely_ missing feature in v8. Maybe if you and i keep complaining loudly enough about it, they'll eventually give us a way to force our destructors to be called.

The fact that v8's performance characteristics are based solely off of Chrome's needs is, IMO, philosophically wrong. One specific app should not determine the destiny of all applications which link to v8. Believe it or not, Chrome is the minority case for v8 - it's used in many, many more applications that Chrome, but yet every single one of them suffers with this limitation because it is useful for Chrome.
 
It's something I would think to be important and useful. I also have Lua bindings for my code, and it can guarantee cleanup when I destroy the interpreter's state.

It is not only important, but CRITICAL for certain types of bound objects, e.g. database handles which must release resources cleanly. Almost all of the classes i've bound so far REQUIRE a destructor call in order for their behaviours to be well-defined. e.g. an sqlite3 database handle, a (FILE*) handle, etc. i've always got to add lots of extra code to my apps to ensure they are cleaned up. Let me reword that - BECAUSE OF CHROME i have to add lots of extra code to manage these destructions.
 
i like Chrome, but i hate that Chrome's needs change the fate of every v8-using application out there. And i hope and pray that someday the v8 developers will recognize this fundamental design flaw and stop coupling v8 to Chrome's speed requirements. If v8's only consideration is Chrome, then it never should have been split out of the Chrome source tree.

--
----- stephan beal
http://wanderinghorse.net/home/stephan/

Anton Muhin

unread,
Nov 30, 2009, 11:33:57 AM11/30/09
to v8-u...@googlegroups.com
On Mon, Nov 30, 2009 at 6:30 PM, Stephan Beal <sgb...@googlemail.com> wrote:
> On Mon, Nov 30, 2009 at 12:17 PM, Abdulla Kamar <abdull...@gmail.com>
> wrote:
>>
>> I've read the discussion, however there was explicit mention of it in the
>> ChangeLog, hence my inquiry.
>
> Hi, Abdulla!
>
> This is a _sorely_ missing feature in v8. Maybe if you and i keep
> complaining loudly enough about it, they'll eventually give us a way to
> force our destructors to be called.

You can always maintain your own list of objects that need to be
destructed and destruct them when you need it. BTW, in most GC
languages that is the only reliable way to release resources (compare,
e.g., w/ Java GC guarantees).

Or you could just force GC several times yourself (e.g. invoke
V8::IdleNotification many times, many > 10).

However, please, double check that you do not retain the objects by yourself.

> The fact that v8's performance characteristics are based solely off of
> Chrome's needs is, IMO, philosophically wrong. One specific app should not
> determine the destiny of all applications which link to v8. Believe it or
> not, Chrome is the minority case for v8 - it's used in many, many more
> applications that Chrome, but yet every single one of them suffers with this
> limitation because it is useful for Chrome.

Chrome is one of most important V8 client. However, I think it's a
very false assumption to think that it's the only client V8 team cares
about: if you could suggest a patch which would help any other client,
I'd surprised if it'd be rejected. Situation would be more involved
if that'd affect performance of Chrome/v8/SunSpider, but that's the
way it is---those are considered to be major benchmarks that v8 team
tries hard not to regress w/o very good reason (like bugfix, e.g.).

hth and yours,
anton.

>
>>
>> It's something I would think to be important and useful. I also have Lua
>> bindings for my code, and it can guarantee cleanup when I destroy the
>> interpreter's state.
>
> It is not only important, but CRITICAL for certain types of bound objects,
> e.g. database handles which must release resources cleanly. Almost all of
> the classes i've bound so far REQUIRE a destructor call in order for their
> behaviours to be well-defined. e.g. an sqlite3 database handle, a (FILE*)
> handle, etc. i've always got to add lots of extra code to my apps to ensure
> they are cleaned up. Let me reword that - BECAUSE OF CHROME i have to add
> lots of extra code to manage these destructions.
>
> i like Chrome, but i hate that Chrome's needs change the fate of every
> v8-using application out there. And i hope and pray that someday the v8
> developers will recognize this fundamental design flaw and stop coupling v8
> to Chrome's speed requirements. If v8's only consideration is Chrome, then
> it never should have been split out of the Chrome source tree.
>
> --
> ----- stephan beal
> http://wanderinghorse.net/home/stephan/
>

Jens Alfke

unread,
Nov 30, 2009, 11:43:49 AM11/30/09
to v8-u...@googlegroups.com

On Nov 30, 2009, at 7:30 AM, Stephan Beal wrote:

> This is a _sorely_ missing feature in v8. Maybe if you and i keep complaining loudly enough about it, they'll eventually give us a way to force our destructors to be called.

Timely release of external references after a context is disposed is important for Chrome as well, as those references hold onto entire DOM trees, which get very large. I've been looking into this as part of the memory task-force on Chromium, and there are some recent and upcoming commits that should help here.

That said, I think a second issue has crept into this discussion: of disposing external refs when V8 exits completely. As mentioned earlier, this shouldn't generally be necessary because V8 exits when the process exits, in which case most external resources get torn down along with the process (file handles, sockets, etc.)

This can be an issue with apps that need to tear down V8 without exiting the process. In that case, though, the native code could keep its own collection of all native resources that are bound to V8 objects, and after closing down V8 it can iterate over all remaining resources and close them.

Another alternative (I believe) would be to repeatedly call V8's low-memory handler until it returns false, which should wring out all possible collectible memory, including weak references.

> The fact that v8's performance characteristics are based solely off of Chrome's needs is, IMO, philosophically wrong. One specific app should not determine the destiny of all applications which link to v8. Believe it or not, Chrome is the minority case for v8 - it's used in many, many more applications that Chrome, but yet every single one of them suffers with this limitation because it is useful for Chrome.

I'm sure you're correct as measured by number of projects (there's surely more than one other project in the world using V8), but I'm pretty sure you're incorrect as measured by number of active users (Chrome is up to 30 million last I heard.)

This is a classic dilemma of open source projects: the design is driven by some consensus of committers. We (Chromium) run into the same issues with WebKit, which has had to adjust from being "Safari's back-end" to supporting multiple browsers with different needs. If a lot of people have a need for V8 to work differently, then they can work on designing and implementing a modification to V8 to allow it to work that way. I can't speak for the V8 team, but if such a patch is architecturally clean and doesn't affect performance for clients that don't need it, it ought to be accepted.

> It is not only important, but CRITICAL for certain types of bound objects, e.g. database handles which must release resources cleanly. Almost all of the classes i've bound so far REQUIRE a destructor call in order for their behaviours to be well-defined. e.g. an sqlite3 database handle, a (FILE*) handle, etc. i've always got to add lots of extra code to my apps to ensure they are cleaned up.

Hm. It's usually considered a truism of garbage collection that finalizers are not guaranteed to be called, and that resources that must be cleaned up should be cleaned up manually. The Java VM specification, for example, explicitly does not guarantee invocation of finalizers.

It is not necessary to close a FILE* explicitly when your process exits; the OS will close the file handle for you. You may need to flush the FILE* if it has unwritten buffered output, but that is the kind of thing you should really be doing manually anyway: what if you write a bunch of stuff without flushing, and then your process keeps running for several days? That data hasn't been written to the file, so anyone looking at the file will see partial data, and in the event of a crash the file will be corrupt.

—Jens

Stephan Beal

unread,
Nov 30, 2009, 12:20:21 PM11/30/09
to v8-u...@googlegroups.com
On Mon, Nov 30, 2009 at 5:33 PM, Anton Muhin <ant...@chromium.org> wrote:
You can always maintain your own list of objects that need to be
destructed and destruct them when you need it.

That's my point - i've got to do the extra work because v8 won't offer a single RunGC() function which i can call before my app exits.
 
Or you could just force GC several times yourself (e.g. invoke
V8::IdleNotification many times, many > 10).

Like all other v8 GC-related hacks, it is just that - a hack.
 
Chrome is one of most important V8 client.  However, I think it's a
very false assumption to think that it's the only client V8 team cares
about: if you could suggest a patch which would help any other client,

Give us a RunGC() function which actually does a full GC run, and i'll be happy. Until v8 gives us a way to force GC to run from client code (regardless of what the hell Chrome wants), i'll be bitching about moaning about this point. This is particularly problematic for those of use who write LIBRARY extensions to chrome, as opposed to APP extensions, as we librarians cannot force any application to add a particular sequence of calls to their apps to clean up "errant objects" which Chrome - er... v8 - refused to clean up for us.

Stephan Beal

unread,
Nov 30, 2009, 12:34:54 PM11/30/09
to v8-u...@googlegroups.com
On Mon, Nov 30, 2009 at 5:43 PM, Jens Alfke <sn...@chromium.org> wrote:
That said, I think a second issue has crept into this discussion: of disposing external refs when V8 exits completely. As mentioned earlier, this shouldn't generally be necessary because V8 exits when the process exits, in which case most external resources get torn down along with the process (file handles, sockets, etc.)

Database connections, for example, must be properly destructed in order to guaranty proper semantics, e.g. that some session isn't being held open on the remote side for a long time.
 
This can be an issue with apps

Key word - apps. i do A LOT of binding in v8:


and not one line of it is an application. i write libraries, and as a library author i cannot control what the application is doing. Almost every single class i have bound to JS as part of that project needs a dtor call in order to guaranty proper semantics. That includes i/o object wrappers, DB handles, ncurses window handles (especially when there are parent/child relationships between the windows), etc. Okay, there are two exceptions in all of my use cases: the libexpat and libcurl wrappers behave a well-defined manner if their objects are destroyed by app exit as opposed to a proper dtor. All others do not.

 
that need to tear down V8 without exiting the process. In that case, though, the native code could keep its own collection of all native resources that are bound to V8 objects, and after closing down V8 it can iterate over all remaining resources and close them.

That work is necessary because, IMO, of v8's and Chrome's requirements being so closely tied. i.e. because Chrome doesn't want v8 to clean up properly ("because it takes too long"), _i_ have to spend dozens of hours coding those features myself (all in all, it _has_ been dozens of hours over the past year). Those dozens of hours are MUCH more than any time Chrome would have needed to shut down if v8 would force a GC at exit. That's what pisses me off the most about this behaviour - that i'm having to do this work for the sake of an application _other_ than the one i'm working on.

Another alternative (I believe) would be to repeatedly call V8's low-memory handler until it returns false, which should wring out all possible collectible memory, including weak references.

== unreliable hack which might work/not work in any given v8 version.
 
I'm sure you're correct as measured by number of projects (there's surely more than one other project in the world using V8), but I'm pretty sure you're incorrect as measured by number of active users (Chrome is up to 30 million last I heard.)

That's very likely true. i'd certainly bet on it.
 
This is a classic dilemma of open source projects: the design is driven by some consensus of committers. We (Chromium) run into the same issues with WebKit, which has had to ,,,team, but if such a patch is architecturally clean and doesn't affect performance for clients that don't need it, it ought to be accepted.

i honestly did look into the patching-submitting process almost a year ago, and found it, quite frankly, far too painful for me to invest the time in. i just wanted to submit documentation patches (i write very good technical docs, if i may say so myself), but the overhead of doing so is downright painful for someone not in the Chromium team.
 
Hm. It's usually considered a truism of garbage collection that finalizers are not guaranteed to be called, and that resources that must be cleaned up should be cleaned up manually. The Java VM specification, for example, explicitly does not guarantee invocation of finalizers.

It's a truism that the destruction order is undefined, but not necessarily that they WON'T be cleaned up.
 
It is not necessary to close a FILE* explicitly when your process exits; the OS will close the file handle for you.

It might not flush it or do any higher-level operations which i've defined for my File-wrapper class to do at destruction. My canonical example here is the TempFile class, which deletes the local file at destruction. On Unix systems we can unlink() a file directly after opening without invalidating the handle, so this is not a problem on Unix. Windows, however, is not quite smart enough to allow that, so this workaround fails on those platforms, and on such platforms, the TempFile class will leave around garbage files after v8 exits.

 
You may need to flush the FILE* if it has unwritten buffered output, but that is the kind of thing you should really be doing manually anyway: what if you write a bunch of stuff without flushing, and then your process keeps running for several days? That data hasn't been written to the file, so anyone looking at the file will see partial data, and in the event of a crash the file will be corrupt.

Agreed, but here the behaviour of v8 shutting down without running a GC (or giving me the opportunity to do so) is IN EFFECT the same as a crash. The objects destroyed this way will behave exactly as they do in the face of a crash.

Anton Muhin

unread,
Nov 30, 2009, 12:42:19 PM11/30/09
to v8-u...@googlegroups.com
Sorry, from the right account.

On Mon, Nov 30, 2009 at 8:39 PM, Anton Muhin <ant...@google.com> wrote:
> Just send a patch which adds such a function---chances are it'd be
> accepted.  If not, you can easily have it in your private build.
>
> A word of caution: running a full GC once doesn't guarantee that all
> the weak references would be released for various reasons, believe me
> none of them is due to make Chrome faster.  The rule of thumb for now
> is to force at least 5 GCs which should collect all the garbage (the
> constant most probably would be reduced later).
>
> BTW, IdleNotification might be still your best bet: there are plans to
> put more and more code which would (eventually) clean all the memory
> V8 holds.
>
> And the last note.  If everything you want, is to call all weak
> callbacks, it could be easily added (just traverse all global handles
> and invoke callback on it).  But it might put your objects into a
> weird state (they are still reachable, but callback has been called on
> them).   Actually, you could probably add something like that into
> global handles teardown method, but you should be careful not to call
> into V8 from the callbacks.
>
> yours,
> anton.
>
>> --
>> ----- stephan beal
>> http://wanderinghorse.net/home/stephan/
>>

Jens Alfke

unread,
Nov 30, 2009, 12:44:00 PM11/30/09
to v8-u...@googlegroups.com

On Nov 30, 2009, at 9:20 AM, Stephan Beal wrote:

> Give us a RunGC() function which actually does a full GC run, and i'll be happy.

while( V8::IdleNotification() )
;

This is not a hack, it's explicitly documented behavior — read the comment above the IdleNotification method in v8.h.
IdleNotification is incremental, and it returns true if there's more cleanup work to be done, or false if it's done all it can.

If you still don't like relying on that, create a V8 patch like this:

void V8::RunGC() {
while( IdleNotification() )
;
}

then test it and submit it for review.

—Jens

Stephan Beal

unread,
Nov 30, 2009, 6:38:14 PM11/30/09
to v8-u...@googlegroups.com
On Mon, Nov 30, 2009 at 6:44 PM, Jens Alfke <sn...@chromium.org> wrote:

On Nov 30, 2009, at 9:20 AM, Stephan Beal wrote:

> Give us a RunGC() function which actually does a full GC run, and i'll be happy.

while( V8::IdleNotification() )
       ;

This is not a hack, it's explicitly documented behavior — read the comment above the IdleNotification method in v8.h.

Thank you very much for that, Jens! The docs are't terribly clear on this function's real use - i never would have surmised it by reading them:

-------------
Optional notification that the embedder is idle.

V8 uses the notification to reduce memory footprint. This call can be used repeatedly if the embedder remains idle. Returns true if the embedder should stop calling IdleNotification until real work has been done. This indicates that V8 has done as much cleanup as it will be able to do.
-------------

Some suggestions for someone who's got commit access:

-----------
Optional notification that the embedder is idle.
-----------

"the embedder", to me, meant something internal to v8. i now understand it to mean "the client [application]".

--------
V8 uses the notification to reduce memory footprint.
--------

_Which_ notification ("the" notification is unclear)?
Recommended rewording: "This notifies v8 that the client application is idle (not using v8) and v8 can run a garbage collection."

Should there be a note about the client using v8::Unlocker in conjunction with this function? (Or is this approach incompatible with Unlocker in some way?)

--------
This call can be used repeatedly if the embedder remains idle.
--------

Again, "the embedder" is somewhat confusing until the meaning ("the client application") finally sets in.

-----------
 Returns true if the embedder should stop calling IdleNotification until real work has been done.
-----------

"real work has been done" is very misleading here. To me that means that my app has done "real work", which it certainly is doing independent of any v8 usage.
Recommended re-wording: "... until v8 has been used sufficiently to create collectible memory."

------------
 This indicates that V8 has done as much cleanup as it will be able to do.
------------

Since the original description doesn't really seem to refer to garbage collection (only indirectly, via "to reduce memory footprint"), i would have never understood that function to be useful as a GC trigger mechanism.

After reading it a few times and comparing that with your comments, it's meaning is now clear, though.

Thanks again!

:-D

Abdulla Kamar

unread,
Nov 30, 2009, 6:46:17 PM11/30/09
to v8-u...@googlegroups.com
It also seems, from my experimentation, that you actually have to call it one more time after it returns true. So the actual sequence should look something like:

while ( !v8::V8::IdleNotification() ) {}
v8::V8::IdleNotification(); 

--



--
Thank you
Abdulla

Jens Alfke

unread,
Nov 30, 2009, 7:00:06 PM11/30/09
to v8-u...@googlegroups.com
On Nov 30, 2009, at 3:46 PM, Abdulla Kamar wrote:

It also seems, from my experimentation, that you actually have to call it one more time after it returns true.


On Tue, Dec 1, 2009 at 10:38 AM, Stephan Beal <sgb...@googlemail.com> wrote:
Some suggestions for someone who's got commit access:

-----------
Optional notification that the embedder is idle.
-----------

"the embedder", to me, meant something internal to v8. i now understand it to mean "the client [application]".

Could each of you please file a bug report against V8 for those issues? Thanks!

—Jens

Abdulla Kamar

unread,
Nov 30, 2009, 8:02:02 PM11/30/09
to v8-u...@googlegroups.com
Sorry, I was wrong, you don't have to make that extra call.

--



--
Thank you
Abdulla

Stephan Beal

unread,
Nov 30, 2009, 8:17:41 PM11/30/09
to v8-u...@googlegroups.com
On Tue, Dec 1, 2009 at 1:00 AM, Jens Alfke <sn...@chromium.org> wrote:
Could each of you please file a bug report against V8 for those issues? Thanks!
 
http://code.google.com/p/v8/issues/detail?id=535
Reply all
Reply to author
Forward
0 new messages