Does using delete keyword effect v8 optimizations of an object?

2,854 views
Skip to first unread message

Zenwolf

unread,
Jun 1, 2012, 2:34:07 AM6/1/12
to v8-u...@googlegroups.com
Greetings all,

Does using the JavaScript "delete" keyword to delete a property from an object effect how v8 will optimize the object? I've read that v8 creates hidden "classes" to represent an object and all its various property configurations. Does deleting a property just flip between two of these hidden classes and is it less efficient than just nulling the local property value?

Secondly, how will v8 handle the case where I have a prototype object with "name" property and also a local property "name" and I delete the local property to expose the prototype value again?

Example:

function Foo() {
    this.name = 'foo';
}

function Bar() {}
Bar.prototype = new Foo();
var bar = new Bar();
bar.name = 'bar';
// later in the program...
delete bar.name; // exposes prototype name again (Foo's name).

Will using delete in such a manner prevent v8 from fully optimizing the code? Or should I not worry about this usage?

Thank you very much for any insight!

Sven Panne

unread,
Jun 1, 2012, 3:29:33 AM6/1/12
to v8-u...@googlegroups.com
We only track property additions, because these are by far the most common case. Deleting a property results in going to "slow mode", i.e. using a dictionary for the object's properties. So as a general rule of thumb, using 'delete' makes thing slower.

What are you trying to achieve exactly? Perhaps there's a way without using 'delete'.

Cheers,
   S.

Zenwolf

unread,
Jun 1, 2012, 11:57:32 AM6/1/12
to v8-u...@googlegroups.com
Thanks for the useful information, Sven!

In my case, I have many instances of the same kind of object. In order to cut down on garbage collection at runtime, I created a pool that contains all instances. When I'm done with an instance, instead of freeing the reference and letting it be GC'd, I put it back into the pool so that I can reuse it.

I thought it would be a good idea to set all default primitive values on the prototype so that only the properties that were actually set would be created as local properties: the rest would be defaults shared across all instances.

When I put something back into the pool, I wanted to delete all local properties to "clean" the instance for reuse. Based on what you are saying, it seems that for performance I should NOT delete the properties, but rather maintain a set of all default properties on each instance, and then null them out.

Followup question based on the above: in a constructor when I establish all of my local properties, is it better to set them to default null value or to a default value of the same type that I intend to use for it (such as empty string, integer, etc.): does the value assigned to a local property in the constructor effect the way optimization will occur for the property?

Thanks very much!

Sven Panne

unread,
Jun 4, 2012, 2:32:45 AM6/4/12
to v8-u...@googlegroups.com
First of all, I would strongly advise against object pooling in a language with GC. Most of the time it creates far more problems than it solves, and one of the few valid use cases is when object creation is extremely costly, like e.g. for data base connections, but it seems that this is not the case for you. When GC takes a large percentage of the whole runtime, the problem is often that objects are retained too long, i.e. a performance bug in user code. Modern GCs should handle rapid allocations of short-lived objects quite well.

Regarding your followup question: In general v8 has the best performance when you pretend that JavaScript has strong typing, so you e.g. only assign numbers to properties which you intend to use in arithmetic, only strings to properties used in string operations, etc.

But assigning dummy values in the constructor looks like a design flaw to me. Either the object is in consistent state without those properties (then there is no need to assign anything), or the object's state really needs some values for these properties (then the dummy values are conceptually wrong). Why do you want to do these dummy assignments?

Cheers,
   S.

Zenwolf

unread,
Jun 4, 2012, 2:26:06 PM6/4/12
to v8-u...@googlegroups.com
Hi Sven,

Object pooling -- If you take a game, for example, where an update loop runs every 33ms or so, GC is one of the major areas that can cause "pausing" and stall the gameplay. Container objects can be created and destroyed at any time and in any number. Even the GC triggered by these objects that are fairly young can lead to paused frames or stalled gameplay. Based on testing, pooling the common game objects and resuing them instead of constanly creating and destroying them led to a marked reduction in GC pauses. This is what led me to go down the pooling path, specific to my case. The creation and destruction of a game object, especially one that participates in an entity system, is expensive to create and destroy.

Property types -- My reason for asking about default property types is due to reading and listening to several presentations where people recommended defining all properties in the constructor. If my object API is flexible, where I do not know when people will set the public property values for a constructed object, I was under the impression that I should still define those properties in the constructor and populate them with default values of the appropriate data type. Later on in the lifecycle of the object, a user will set the updated values based on the timing of the parent code. If this doesn't matter for performance, I would prefer to not define them with local default values, and the user will set/create these properties outside of the constructor. However, if for performance reasons the local default values in the constructor are better for V8 optimization, I would go that route since performance is crucial for me.

I hope that makes sense now. Thanks again!

Angel Java Lopez

unread,
Jun 4, 2012, 2:40:27 PM6/4/12
to v8-u...@googlegroups.com
Hmmm... interesting topic.

I'm playing with implements a key value in-memory store, using 

values[key] = value;

when values initially is {}.

When removing a key, I'm using

delete values[key]

Maybe, I should do

values[key] = null

and count the deletions. When reaching some count, I could copy all the surviving keys (that is, that with associated value != null) to a new object.

(My store is a tree. That is, if the key is users:1:name, the top store has key 'users' pointing to a second level store, that has key 1 that points to a third store that have key 'name'. The numeric keys are stored in a "big integer set" implementation. Only alphanumeric keys are stored in associative arrays/objects. So, I expect few keys per node level).

Comments?

Angel "Java" Lopez

Sven Panne

unread,
Jun 5, 2012, 2:28:21 AM6/5/12
to v8-u...@googlegroups.com
Regarding object pooling: What you describe is exactly one of the use cases where one should *not* use object pooling. Incremental collectors are very good at disposing short-lived objects without any noticeable pauses, so unless you are doing heavy resource acquisition on object creation, don't do pooling. This only leads to a heavier load on the GC, can easily lead to space leaks, and in general a good pooling strategy is not that easy as it might sound. If your program's performance is really, really bound by object creation, an ugly, but more promising route is to go "the imperative way", avoiding object creation as much as possible and mutating objects like hell. But in general that means restructuring your program, which might be hard, so I would only do this when I'm totally sure about the bottlenecks.

Regarding property types: I very much doubt that there are clean use cases of a "flexible API", where some property values are set in the constructor and some later. Things like this are a strong hint that the API has a flaw, and leads to obscure rules like "Don't call the foo function before bar and baz have been called on the object". Break down the objects/classes/..., and this becomes a non-problem.

Cheers,
   S.

Sven Panne

unread,
Jun 5, 2012, 2:42:17 AM6/5/12
to v8-u...@googlegroups.com
When you are using an object as a hash map, using delete is OK, because then the object is very probably already in dictionary (= hash map) mode. Playing GC by hand is not necessary and almost always the wrong thing, anyway.

Is there a semantic reason for the structuring of the keys or do you intentionally want to use a trie? If the keys are conceptually flat, you can perhaps get better performance by just letting the JavaScript engine do the hashing of the flat keys. Mixing hashing and tree structures is often not a good idea: IIRC, there is an exercise in one of the classic Knuth books where you have to prove that a "clever" hash table with binary trees as buckets is worse than a simpler hash table with some probing strategy or linear chaining (don't remember).

What is a "big integer set implementation"?

Cheers,
   S.

Angel Java Lopez

unread,
Jun 5, 2012, 4:58:51 AM6/5/12
to v8-u...@googlegroups.com
Thanks for the info. Hmmm.. interesting, I should read Knuth and think about the alternatives. And read V8 code to understand its hash management, and array implementation.

"big integer set implementation" refers, in my jargon, to an sparse array, possible implemented as a tree.

The best way to describe my intention is with code:

BigArray able me to have an array with a value under key 1, and under key 1000000, without allocating all the intermediate values. I don't know if V8 has a similar internal implementation, is it? Apparently, yes. I just tried in node

var arr = []
arr[1] = 1
arr[40000000] = 2
arr[400000000] = 3

To implement SortedSet a la Redis, I should have an efficient way of traversing the existing index key in numerical order, and that BigArray implementation give me that feature. How to retrieve the "used keys" in the about array? Or maybe I should revert to objects with keys?

In some operations, I need to retrieve the last 100 keys, or the first 100 keys.

Then, after that, I want to implement in Javascript a BitArray (code in above link). Using a BigArray of bytes in C# (long I presume in Javascript), I can turn on or off a bit (addresses by bit position, that is, bit #17 is the bit #2 in the second byte of the BigArray).

To emulate Redis

sadd myset 1   // add 1 to set my set

I want to use a BitArray

To emulate Redis

set users:1 "adam"

I want to have associated to "users" a BigArray, and "adam" fit in the slot 1. That is the reason to have a structured key. An activity feed of message to that user, could be then implemented with

sset users:1:messages 120345

internally object referenced by key users:1:messages is a bit set.

But enough Redis emulation for this list ;-). I will think about your suggestion for flat keys.

It's a pet project, but interesting for me. 

Not know limit for memory in 64 bits? I just found
Any memory limit not related to hardware?

Zenwolf

unread,
Jun 5, 2012, 1:20:23 PM6/5/12
to v8-u...@googlegroups.com
Hi Sven,

Props -- I am setting all properties in the constructor. I am just allowing them to be changed via the API, much like a setter would allow you to change a property value (except I am using public properties for performance reasons to reduce function calls), so I think that is pretty much covered. You also answered the question about delete, which is very useful. Thanks!

Pooling -- I have read about several other projects implementing object pooling to good effects for things such as particle effects, etc, where a large number of similar objects are repeatedly created and destroyed. In addition, there have been people recommending to avoid the use of object literals, array literals, anonymous functions and native functions that create and throw out new objects (splice, slice, etc.) in order to avoid GC in critical areas. I think that these are all pretty specific to games and may be not recommended or useful for other types of applications that are not so performance sensitive (I certainly wouldn't use pooling in other cases).

I really appreciate the info you have shared so far! I am interested to learn more about the space leaks you mentioned, if you have any more info on that (or links I can read).
Reply all
Reply to author
Forward
0 new messages