As usual with V8 this is quite tricky to make a global statement.

There are several forces at play here:
1. Normal objects have hidden classes, maintaining them is a an additional 
cost per new property
2. All property names for objects have to be internalized and get added to 
the global StringTable
3. ES6 Maps use a different, more compact, HashTable implementation than 
for instance the internal string table or the hash table used for 
dictionary properties
4. Dictionary properties have to keep track of the enumeration index and 
the descriptors (readable, enumerable, configurable), which makes them use 
at least 30% more space.

For the details about how V8 handles different object properties you might 
want to look at https://v8project.blogspot.de/2017/08/fast-properties.html.
To gather better insights there is an experimental tool from the gc team 
available under https://mlippautz.github.io/v8-heap-stats/.

I hope this clarifies a few things.

On Monday, November 27, 2017 at 10:39:16 PM UTC+1, Jonathan Otto wrote:
>
> I switched to a Map which looks like it may have solved the issue.
>
> See this: https://jsperf.com/es6-map-vs-object-properties/
>
> And, running Node.js --perf with the code from that jsperf yields the 
> following (on Node v8.9.1 which, according to process.versions, is V8 
> 6.1.534.47):
>
> *Map (15.7% in GC)*
>  [Summary]:
>    ticks  total  nonlib   name
>     903   68.1%   68.4%  JavaScript
>     395   29.8%   29.9%  C++
>     208   15.7%   15.7%  GC
>       5    0.4%          Shared libraries
>      23    1.7%          Unaccounted
>
>
>  [C++]:
>    ticks  total  nonlib   name
>      91    6.9%    6.9%  t v8::internal::Scavenger::ScavengeObject(v8::
> internal::HeapObject**, v8::internal::HeapObject*)
>      38    2.9%    2.9%  t v8::internal::OrderedHashTable<v8::internal::
> OrderedHashMap, 2>::Rehash(v8::internal::Handle<v8::internal::
> OrderedHashMap>, int)
>      36    2.7%    2.7%  T v8::internal::Runtime_GenerateRandomNumbers(int
> , v8::internal::Object**, v8::internal::Isolate*)
>      36    2.7%    2.7%  T v8::internal::IncrementalMarking::Step(unsigned 
> long, v8::internal::IncrementalMarking::CompletionAction, v8::internal::
> IncrementalMarking::ForceCompletionAction, v8::internal::StepOrigin)
>      30    2.3%    2.3%  T v8::internal::Heap::Scavenge()
>      25    1.9%    1.9%  T v8::internal::Heap::
> AllocateFixedArrayWithFiller(int, v8::internal::PretenureFlag, v8::
> internal::Object*)
>      24    1.8%    1.8%  t node::(anonymous namespace)::ContextifyScript::
> New(v8::FunctionCallbackInfo<v8::Value> const&)
>      14    1.1%    1.1%  t v8::internal::(anonymous namespace)::
> GetSimpleHash(v8::internal::Object*)
>
>
> *Object (26.8% in GC)*
>  [Summary]:
>    ticks  total  nonlib   name
>     698   32.2%   32.2%  JavaScript
>    1417   65.3%   65.4%  C++
>     581   26.8%   26.8%  GC
>       2    0.1%          Shared libraries
>      53    2.4%          Unaccounted
>
>
>  [C++]:
>    ticks  total  nonlib   name
>     269   12.4%   12.4%  T v8::internal::IncrementalMarking::Step(unsigned 
> long, v8::internal::IncrementalMarking::CompletionAction, v8::internal::
> IncrementalMarking::ForceCompletionAction, v8::internal::StepOrigin)
>     148    6.8%    6.8%  t v8::internal::HashTable<v8::internal::
> NameDictionary, v8::internal::NameDictionaryShape>::Rehash(v8::internal::
> NameDictionary*)
>     122    5.6%    5.6%  T v8::internal::Heap::Scavenge()
>     107    4.9%    4.9%  t v8::internal::Scavenger::ScavengeObject(v8::
> internal::HeapObject**, v8::internal::HeapObject*)
>     103    4.7%    4.8%  T v8::internal::HashTable<v8::internal::
> StringTable, v8::internal::StringTableShape>::Rehash(v8::internal::
> StringTable*)
>      91    4.2%    4.2%  T v8::internal::StringTable::LookupKey(v8::
> internal::Isolate*, v8::internal::StringTableKey*)
>      82    3.8%    3.8%  t v8::internal::LookupIterator::State v8::
> internal::LookupIterator::LookupInRegularHolder<false>(v8::internal::Map*, 
> v8::internal::JSReceiver*)
>      48    2.2%    2.2%  T v8::internal::Heap::
> AllocateFixedArrayWithFiller(int, v8::internal::PretenureFlag, v8::
> internal::Object*)
>      41    1.9%    1.9%  T v8::internal::String::SlowEquals(v8::internal::
> String*)
>
>
> If I plot out the actual duration of the add/update operation to either a 
> Map or Object, they're both almost equivalent as N increases, but the 
> memory usage and GC activity *around* that add/update for the Object is 
> much higher. In fact, depending on the length of the random string being 
> created, the Object often maxes out the heap and crashes Node.js. (I 
> experimented with increasing --max_old_space_size up to 10000) There's also 
> a point (random strings of length 5, with N of 8,000,000) where even if 
> your heap is large enough to hold all the strings, the adding/appending to 
> an Object just seizes up (and Map still works).
>
> On Thursday, November 23, 2017 at 12:59:06 AM UTC-8, Camillo Bruni wrote:
>>
>> Hi Jonathan, 
>>
>> this seems suspicious. Would it be possible for you to write a standalone 
>> repro?
>> Without further information it is hard to asses what exactly might be 
>> going wrong here.
>>
>> Cheers,
>> Camillo
>>
>> On Wednesday, November 22, 2017 at 1:29:50 AM UTC+1, Jonathan Otto wrote:
>>>
>>> I have a plain JavaScript object that looks like:
>>>
>>> {
>>>   sha256a: { id, fieldA, fieldB, fieldC },
>>>   sha256b: { id, fieldA, fieldB, fieldC },
>>>   ...
>>> }
>>>
>>> and it seems like when I get over ~50,000 sha's then I start to have 
>>> high CPU usage (~3%) when adding a key or changing a value for an existing 
>>> key - note I am adding/changing keys once or twice per second. Naively I'm 
>>> wondering if the GC is traversing the entire object on each addition or 
>>> change and whether there's a cliff where that falls off.
>>>
>>> Is there a better way to manage a local store in JavaScript?
>>>
>>

-- 
-- 
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.

Reply via email to