Last active
April 10, 2025 11:52
-
-
Save wentout/c155aa40580da0c62a6639af89460976 to your computer and use it in GitHub Desktop.
Struct Sizes Comparison
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
'use strict'; | |
const count = 1_000_000_000; | |
console.time('finished in'); | |
const myArr = []; | |
let i = 0; | |
const handler = () => { | |
console.timeEnd('finished in'); | |
console.log(`made [ ${i-1} ] elements`); | |
}; | |
for (; i <= count; i++) { | |
const str = new String(i); | |
const len = str.length; | |
let num = 0; | |
const caption = str.split('').reverse().reduce((arr, value) => { | |
if (num > 2 && num % 3 === 0) { | |
arr.unshift('_'); | |
} | |
num++; | |
arr.unshift(value); | |
return arr; | |
}, []).join(''); | |
const item = `item : ${caption}`; | |
try { | |
myArr.push(item); | |
} catch (error) { | |
console.error(error); | |
handler(); | |
process.exit(); | |
} | |
if (i % 100_000 === 0) { | |
console.log(item); | |
} | |
} | |
handler(); | |
/* | |
item : 56_900_000 | |
<--- Last few GCs ---> | |
[92570:0x12148190] 77070 ms: Mark-Compact 4056.4 (4132.8) -> 4042.1 (4134.5) MB, 2487.88 / 0.00 ms (average mu = 0.124, current mu = 0.009) allocation failure; scavenge might not succeed | |
[92570:0x12148190] 79301 ms: Mark-Compact 4057.9 (4134.5) -> 4043.8 (4136.0) MB, 2204.34 / 0.00 ms (average mu = 0.075, current mu = 0.012) allocation failure; scavenge might not succeed | |
<--- JS stacktrace ---> | |
FATAL ERROR: Ineffective mark-compacts near heap limit Allocation failed - JavaScript heap out of memory | |
----- Native stack trace ----- | |
1: 0xb8d11b node::OOMErrorHandler(char const*, v8::OOMDetails const&) [node] | |
2: 0xf01b70 v8::Utils::ReportOOMFailure(v8::internal::Isolate*, char const*, v8::OOMDetails const&) [node] | |
3: 0xf01e57 v8::internal::V8::FatalProcessOutOfMemory(v8::internal::Isolate*, char const*, v8::OOMDetails const&) [node] | |
4: 0x1113aa5 [node] | |
5: 0x1114034 v8::internal::Heap::RecomputeLimits(v8::internal::GarbageCollector) [node] | |
6: 0x112af24 v8::internal::Heap::PerformGarbageCollection(v8::internal::GarbageCollector, v8::internal::GarbageCollectionReason, char const*) [node] | |
7: 0x112b73c v8::internal::Heap::CollectGarbage(v8::internal::AllocationSpace, v8::internal::GarbageCollectionReason, v8::GCCallbackFlags) [node] | |
8: 0x1101a41 v8::internal::HeapAllocator::AllocateRawWithLightRetrySlowPath(int, v8::internal::AllocationType, v8::internal::AllocationOrigin, v8::internal::AllocationAlignment) [node] | |
9: 0x1102bd5 v8::internal::HeapAllocator::AllocateRawWithRetryOrFailSlowPath(int, v8::internal::AllocationType, v8::internal::AllocationOrigin, v8::internal::AllocationAlignment) [node] | |
10: 0x10e0226 v8::internal::Factory::NewFillerObject(int, v8::internal::AllocationAlignment, v8::internal::AllocationType, v8::internal::AllocationOrigin) [node] | |
11: 0x153c086 v8::internal::Runtime_AllocateInYoungGeneration(int, unsigned long*, v8::internal::Isolate*) [node] | |
12: 0x7ce451e99ef6 | |
Aborted (core dumped) | |
*/ | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
'use strict'; | |
(function () { | |
const count = 1_000_000; | |
console.time('finished in'); | |
const myMap = new Map(); | |
let i = 0; | |
const handler = () => { | |
console.timeEnd('finished in'); | |
console.log(`made [ ${i - 1} ] elements`); | |
}; | |
for (; i <= count; i++) { | |
const str = new String(i); | |
const len = str.length; | |
let num = 0; | |
const caption = str.split('').reverse().reduce((arr, value) => { | |
if (num > 2 && num % 3 === 0) { | |
arr.unshift('_'); | |
} | |
num++; | |
arr.unshift(value); | |
return arr; | |
}, []).join(''); | |
const item = `item : ${caption}`; | |
try { | |
myMap.set(item, item); | |
} catch (error) { | |
console.error(error); | |
handler(); | |
process.exit(); | |
} | |
if (i % 100_000 === 0) { | |
console.log(item); | |
} | |
} | |
handler(); | |
console.time('access time'); | |
console.log(myMap.has('item : 1_000')); | |
console.timeEnd('access time'); // 0.03ms | |
})(); | |
/* | |
item : 16_700_000 | |
RangeError: Map maximum size exceeded | |
at Map.set (<anonymous>) | |
at Object.<anonymous> (/code/_dev_tests/StructSizes/MapDeepness.js:33:15) | |
at Module._compile (node:internal/modules/cjs/loader:1469:14) | |
at Module._extensions..js (node:internal/modules/cjs/loader:1548:10) | |
at Module.load (node:internal/modules/cjs/loader:1288:32) | |
at Module._load (node:internal/modules/cjs/loader:1104:12) | |
at Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:173:12) | |
at node:internal/main/run_main_module:28:49 | |
finished in: 22.293s | |
made [ 16777215 ] elements | |
*/ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
'use strict'; | |
const count = 1_000_000_000; | |
console.time('finished in'); | |
const myObj = new Object(); | |
let i = 0; | |
const handler = () => { | |
console.timeEnd('finished in'); | |
console.log(`made [ ${i-1} ] elements`); | |
}; | |
for (; i <= count; i++) { | |
const str = new String(i); | |
const len = str.length; | |
let num = 0; | |
const caption = str.split('').reverse().reduce((arr, value) => { | |
if (num > 2 && num % 3 === 0) { | |
arr.unshift('_'); | |
} | |
num++; | |
arr.unshift(value); | |
return arr; | |
}, []).join(''); | |
const item = `item : ${caption}`; | |
try { | |
myObj[item] = item; | |
} catch (error) { | |
console.error(error); | |
handler(); | |
process.exit(); | |
} | |
if (i % 100_000 === 0) { | |
console.log(item); | |
} | |
} | |
handler(); | |
/* | |
just stopped here | |
item : 8_300_000 | |
*/ | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
'use strict'; | |
(function () { | |
const count = 1_000_000_000; | |
console.time('finished in'); | |
var last = { | |
prev: null, | |
item: null, | |
next: null | |
}; | |
let i = 0; | |
const handler = () => { | |
console.timeEnd('finished in'); | |
console.log(`made [ ${i - 1} ] elements`); | |
}; | |
for (; i <= count; i++) { | |
const str = new String(i); | |
const len = str.length; | |
let num = 0; | |
const caption = str.split('').reverse().reduce((arr, value) => { | |
if (num > 2 && num % 3 === 0) { | |
arr.unshift('_'); | |
} | |
num++; | |
arr.unshift(value); | |
return arr; | |
}, []).join(''); | |
const item = `item : ${caption}`; | |
try { | |
const current = { | |
prev: last, | |
item: item, | |
next: null | |
}; | |
last.next = current; | |
last = current; | |
} catch (error) { | |
console.error(error); | |
handler(); | |
process.exit(); | |
} | |
if (i % 100_000 === 0) { | |
console.log(item); | |
} | |
} | |
handler(); | |
})(); | |
/* | |
item : 37_800_000 | |
<--- Last few GCs ---> | |
[94039:0x40fd7240] 115606 ms: Mark-Compact 4053.8 (4140.2) -> 4039.6 (4142.0) MB, 2779.59 / 0.00 ms (average mu = 0.229, current mu = 0.011) allocation failure; scavenge might not succeed | |
[94039:0x40fd7240] 119225 ms: Mark-Compact 4056.7 (4143.2) -> 4042.5 (4144.7) MB, 3592.37 / 0.00 ms (average mu = 0.115, current mu = 0.007) allocation failure; scavenge might not succeed | |
<--- JS stacktrace ---> | |
FATAL ERROR: Reached heap limit Allocation failed - JavaScript heap out of memory | |
----- Native stack trace ----- | |
1: 0xb8d11b node::OOMErrorHandler(char const*, v8::OOMDetails const&) [node] | |
2: 0xf01b70 v8::Utils::ReportOOMFailure(v8::internal::Isolate*, char const*, v8::OOMDetails const&) [node] | |
3: 0xf01e57 v8::internal::V8::FatalProcessOutOfMemory(v8::internal::Isolate*, char const*, v8::OOMDetails const&) [node] | |
4: 0x1113aa5 [node] | |
5: 0x112b928 v8::internal::Heap::CollectGarbage(v8::internal::AllocationSpace, v8::internal::GarbageCollectionReason, v8::GCCallbackFlags) [node] | |
6: 0x1101a41 v8::internal::HeapAllocator::AllocateRawWithLightRetrySlowPath(int, v8::internal::AllocationType, v8::internal::AllocationOrigin, v8::internal::AllocationAlignment) [node] | |
7: 0x1102bd5 v8::internal::HeapAllocator::AllocateRawWithRetryOrFailSlowPath(int, v8::internal::AllocationType, v8::internal::AllocationOrigin, v8::internal::AllocationAlignment) [node] | |
8: 0x10e0226 v8::internal::Factory::NewFillerObject(int, v8::internal::AllocationAlignment, v8::internal::AllocationType, v8::internal::AllocationOrigin) [node] | |
9: 0x153c086 v8::internal::Runtime_AllocateInYoungGeneration(int, unsigned long*, v8::internal::Isolate*) [node] | |
10: 0x7039c3ed9ef6 | |
Aborted (core dumped) | |
*/ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
'use strict'; | |
(function () { | |
const count = 1_000_000; | |
console.time('finished in'); | |
const init = { | |
name: 'init', | |
prev: null, | |
get init() { | |
return init; | |
} | |
}; | |
const ids = new Map(); | |
const prevs = new Map(); | |
const nexts = new Map(); | |
var last = init; | |
let i = 0; | |
const handler = () => { | |
console.timeEnd('finished in'); | |
console.log(`made [ ${i - 1} ] elements`); | |
}; | |
for (; i <= count; i++) { | |
const str = new String(i); | |
const len = str.length; | |
let num = 0; | |
const caption = str.split('').reverse().reduce((arr, value) => { | |
if (num > 2 && num % 3 === 0) { | |
arr.unshift('_'); | |
} | |
num++; | |
arr.unshift(value); | |
return arr; | |
}, []).join(''); | |
const name = `item : ${caption}`; | |
try { | |
const props = { | |
prev: { | |
value: last, | |
enumerable: true, | |
configurable: true | |
}, | |
name: { | |
value: name, | |
enumerable: true, | |
configurable: true | |
}, | |
next: { | |
value: null, | |
enumerable: true, | |
configurable: true | |
} | |
}; | |
const current = Object.create(last, props); | |
Object.defineProperty(current, name, { | |
value: current, | |
enumerable: true, | |
configurable: true | |
}); | |
Object.defineProperty(current, 'self', { | |
value: current, | |
enumerable: true, | |
configurable: true | |
}); | |
Object.defineProperty(last, 'next', { | |
value: current, | |
enumerable: true, | |
configurable: true | |
}); | |
prevs.set(current, last); | |
nexts.set(last, current); | |
last = current; | |
ids.set(name, current); | |
} catch (error) { | |
console.error(error); | |
handler(); | |
process.exit(); | |
} | |
if (i % 100_000 === 0) { | |
console.log(name); | |
} | |
} | |
handler(); | |
console.time('access time'); | |
const first = last['item : 0']; | |
console.log('proto chain object:\n', first); | |
console.timeEnd('access time'); // 5s | |
console.log('\n\n\n'); | |
console.time('access time map [item : 0]'); | |
console.log('map proto object:\n', ids.get('item : 0')); | |
console.timeEnd('access time map [item : 0]'); // 0.3ms | |
console.log('\n\n\n'); | |
console.time('access time proto'); | |
console.log('proto object:\n', Reflect.getPrototypeOf(last)); | |
console.timeEnd('access time proto'); | |
console.log('\n\n\n'); | |
console.time('access time prev'); | |
console.log('prev object:\n', last.prev); | |
console.timeEnd('access time prev'); | |
console.log('\n\n\n'); | |
console.time('access time prevs'); | |
const proto = prevs.get(last); | |
console.log('prevs object:\n', proto); | |
console.timeEnd('access time prevs'); | |
console.log('\n\n\n'); | |
console.time('access time nexts'); | |
const pnext = nexts.get(proto); | |
console.log('nexts object:\n', pnext); | |
console.timeEnd('access time nexts'); | |
console.log('\n\n\n'); | |
console.time('access time first → nexts'); | |
const first_next = nexts.get(first); | |
console.log('first → nexts object:\n', first_next); | |
console.timeEnd('access time first → nexts'); | |
console.log('\n\n\n'); | |
console.time('access time first → nexts → next'); | |
const first_next_next = nexts.get(first_next); | |
console.log('first → nexts object:\n', first_next_next); | |
console.timeEnd('access time first → nexts → next'); | |
console.log('\n\n\n'); | |
console.time('access time first_next_next proto'); | |
console.log('proto object:\n', Reflect.getPrototypeOf(first_next_next)); | |
console.timeEnd('access time first_next_next proto'); // 0.2ms | |
console.log('\n\n\n'); | |
console.time('access time map [item : 549_997]'); | |
console.log('map [549_997] object:\n', ids.get('item : 549_997')); | |
console.timeEnd('access time map [item : 549_997]'); // 0.3ms | |
console.log('\n\n\n'); | |
})(); | |
/* | |
item : 8_300_000 | |
<--- Last few GCs ---> | |
[96963:0xd1b0240] 118344 ms: Mark-Compact 3766.1 (4128.7) -> 3749.8 (4126.0) MB, 5095.31 / 0.00 ms (average mu = 0.067, current mu = 0.015) allocation failure; scavenge might not succeed | |
[96963:0xd1b0240] 118445 ms: Scavenge 3770.1 (4127.0) -> 3759.3 (4127.0) MB, 18.42 / 0.00 ms (average mu = 0.067, current mu = 0.015) allocation failure; | |
[96963:0xd1b0240] 118544 ms: Scavenge 3773.0 (4127.0) -> 3765.1 (4129.5) MB, 37.28 / 0.00 ms (average mu = 0.067, current mu = 0.015) allocation failure; | |
<--- JS stacktrace ---> | |
FATAL ERROR: Ineffective mark-compacts near heap limit Allocation failed - JavaScript heap out of memory | |
----- Native stack trace ----- | |
1: 0xb8d11b node::OOMErrorHandler(char const*, v8::OOMDetails const&) [node] | |
2: 0xf01b70 v8::Utils::ReportOOMFailure(v8::internal::Isolate*, char const*, v8::OOMDetails const&) [node] | |
3: 0xf01e57 v8::internal::V8::FatalProcessOutOfMemory(v8::internal::Isolate*, char const*, v8::OOMDetails const&) [node] | |
4: 0x1113aa5 [node] | |
5: 0x1114034 v8::internal::Heap::RecomputeLimits(v8::internal::GarbageCollector) [node] | |
6: 0x112af24 v8::internal::Heap::PerformGarbageCollection(v8::internal::GarbageCollector, v8::internal::GarbageCollectionReason, char const*) [node] | |
7: 0x112b73c v8::internal::Heap::CollectGarbage(v8::internal::AllocationSpace, v8::internal::GarbageCollectionReason, v8::GCCallbackFlags) [node] | |
8: 0x1101a41 v8::internal::HeapAllocator::AllocateRawWithLightRetrySlowPath(int, v8::internal::AllocationType, v8::internal::AllocationOrigin, v8::internal::AllocationAlignment) [node] | |
9: 0x1102bd5 v8::internal::HeapAllocator::AllocateRawWithRetryOrFailSlowPath(int, v8::internal::AllocationType, v8::internal::AllocationOrigin, v8::internal::AllocationAlignment) [node] | |
10: 0x10df2f6 v8::internal::Factory::AllocateRaw(int, v8::internal::AllocationType, v8::internal::AllocationAlignment) [node] | |
11: 0x10d0a6c v8::internal::FactoryBase<v8::internal::Factory>::AllocateRawArray(int, v8::internal::AllocationType) [node] | |
12: 0x10d0bd4 v8::internal::FactoryBase<v8::internal::Factory>::NewFixedArrayWithFiller(v8::internal::Handle<v8::internal::Map>, int, v8::internal::Handle<v8::internal::Oddball>, v8::internal::AllocationType) [node] | |
13: 0x13f3d1d v8::internal::Handle<v8::internal::NameDictionary> v8::internal::HashTable<v8::internal::NameDictionary, v8::internal::NameDictionaryShape>::New<v8::internal::Isolate>(v8::internal::Isolate*, int, v8::internal::AllocationType, v8::internal::MinimumCapacity) [node] | |
14: 0x13f5049 v8::internal::Handle<v8::internal::NameDictionary> v8::internal::BaseNameDictionary<v8::internal::NameDictionary, v8::internal::NameDictionaryShape>::New<v8::internal::Isolate>(v8::internal::Isolate*, int, v8::internal::AllocationType, v8::internal::MinimumCapacity) [node] | |
15: 0x13f50c9 v8::internal::Handle<v8::internal::NameDictionary> v8::internal::NameDictionary::New<v8::internal::Isolate>(v8::internal::Isolate*, int, v8::internal::AllocationType, v8::internal::MinimumCapacity) [node] | |
16: 0x1356c90 v8::internal::JSObject::MigrateToMap(v8::internal::Isolate*, v8::internal::Handle<v8::internal::JSObject>, v8::internal::Handle<v8::internal::Map>, int) [node] | |
17: 0x135a0bc v8::internal::JSObject::OptimizeAsPrototype(v8::internal::Handle<v8::internal::JSObject>, bool) [node] | |
18: 0x13c794d v8::internal::Map::GetObjectCreateMap(v8::internal::Isolate*, v8::internal::Handle<v8::internal::HeapObject>) [node] | |
19: 0x1348bc2 v8::internal::JSObject::ObjectCreate(v8::internal::Isolate*, v8::internal::Handle<v8::internal::Object>) [node] | |
20: 0x154580b v8::internal::Runtime_ObjectCreate(int, unsigned long*, v8::internal::Isolate*) [node] | |
21: 0x70589e699ef6 | |
Aborted (core dumped) | |
*/ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
'use strict'; | |
(function () { | |
const count = 1_000_000; | |
console.time('finished in'); | |
const mySet = new Set(); | |
let i = 0; | |
const handler = () => { | |
console.timeEnd('finished in'); | |
console.log(`made [ ${i - 1} ] elements`); | |
}; | |
for (; i <= count; i++) { | |
const str = new String(i); | |
const len = str.length; | |
let num = 0; | |
const caption = str.split('').reverse().reduce((arr, value) => { | |
if (num > 2 && num % 3 === 0) { | |
arr.unshift('_'); | |
} | |
num++; | |
arr.unshift(value); | |
return arr; | |
}, []).join(''); | |
const item = `item : ${caption}`; | |
try { | |
mySet.add(item); | |
} catch (error) { | |
console.error(error); | |
handler(); | |
process.exit(); | |
} | |
if (i % 100_000 === 0) { | |
console.log(item); | |
} | |
} | |
handler(); | |
console.time('access time'); | |
console.log(mySet.has('item : 1_000')); | |
console.timeEnd('access time'); // 0.03ms | |
})(); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
'use strict'; | |
(function () { | |
const count = 1_000_000_000; | |
console.time('finished in'); | |
const myMap = new WeakMap(); | |
let i = 0; | |
let current = { | |
item: null, | |
prev: null, | |
next: null | |
}; | |
const handler = () => { | |
console.timeEnd('finished in'); | |
console.log(`made [ ${i - 1} ] elements`); | |
}; | |
for (; i <= count; i++) { | |
const str = new String(i); | |
const len = str.length; | |
let num = 0; | |
const caption = str.split('').reverse().reduce((arr, value) => { | |
if (num > 2 && num % 3 === 0) { | |
arr.unshift('_'); | |
} | |
num++; | |
arr.unshift(value); | |
return arr; | |
}, []).join(''); | |
const item = `item : ${caption}`; | |
const key = { | |
item, | |
prev: current, | |
next: null | |
}; | |
try { | |
myMap.set(key, item); | |
current.next = key; | |
current = key; | |
} catch (error) { | |
console.error(error); | |
handler(); | |
process.exit(); | |
} | |
if (i % 100_000 === 0) { | |
console.log(item); | |
} | |
} | |
handler(); | |
console.time('access time'); | |
console.log(myMap.get(current)); | |
console.timeEnd('access time'); // 0.03ms | |
})(); | |
/* | |
finished in: 1.403s | |
made [ 1000000 ] elements | |
item : 1_000_000 | |
access time: 0.03ms | |
дальше очень долго и "подвисло" тут | |
item : 5_500_000 | |
*/ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
'use strict'; | |
(function () { | |
const count = 1_000_000_000; | |
console.time('finished in'); | |
const mySet = new WeakSet(); | |
let i = 0; | |
let current = { | |
item: null, | |
prev: null, | |
next: null | |
}; | |
const handler = () => { | |
console.timeEnd('finished in'); | |
console.log(`made [ ${i - 1} ] elements`); | |
}; | |
for (; i <= count; i++) { | |
const str = new String(i); | |
const len = str.length; | |
let num = 0; | |
const caption = str.split('').reverse().reduce((arr, value) => { | |
if (num > 2 && num % 3 === 0) { | |
arr.unshift('_'); | |
} | |
num++; | |
arr.unshift(value); | |
return arr; | |
}, []).join(''); | |
const item = `item : ${caption}`; | |
const key = { | |
item, | |
prev: current, | |
next: null | |
}; | |
try { | |
mySet.add(key); | |
current.next = key; | |
current = key; | |
} catch (error) { | |
console.error(error); | |
handler(); | |
process.exit(); | |
} | |
if (i % 100_000 === 0) { | |
console.log(item); | |
} | |
} | |
handler(); | |
console.time('access time'); | |
console.log(mySet.has(current)); | |
console.timeEnd('access time'); // 0.03ms | |
})(); | |
/* | |
finished in: 1.092s | |
made [ 1000000 ] elements | |
true | |
access time: 0.385ms | |
дальше очень медленно и просто зависло на | |
item : 11_100_000 | |
*/ |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment