1

How big is the difference in memory consumption when storing for Example a reference to an HTML Element in memory vs a String or a Number?

const el = document.getElementById("myEl");

const myCache = new Set()

// store reference to element
myCache.add(el);

// VS store a random string
myCache.add("someStr");

// VS store a random number
myCache.add(0);

How does this look in the Memory, what is the most memory friendly solution out of them.

inux
  • 99
  • 7

2 Answers2

3

Let's see the memory consumption from chrome heap dump first.

A Set of 1509 strings each of 144 characters consumes 231776 bytes: enter image description here

A Set of 1509 strings each of 72 characters consumes 111056 bytes: enter image description here

A Set of 1509 strings each of 36 characters consumes 50696 bytes: enter image description here

A Set of 1509 elements consumes 20516 bytes: enter image description here

A Set of 1509 numbers also consumes 20516 bytes: enter image description here

So, size of the Set of string varies with the size of each item length but memory size is consistent for elements and number.

Now coming to answering your question. The most memory efficient approach may vary depending on the use-case.

A set of element will actually store the element references. The size for object reference in JS is 8bytes.

A set of element reference may looks to be a solution which consumes consistent memory as the set is only holding the references to the element and the memory for the element is already allocated as it is part of the DOM. So nothing really increasing as such.

But, one problem with creating a set with element references is, if we do not remove the element reference after the element is removed from the DOM, due to the element reference hold in the set, it will keep consuming the memory allocated for that removed element. If on the page the add / remove element happens very frequently and the set is holding all element references, it can cause memory leak. In such situation we must be removing the removed element references from the set. Element.isConnected is a boolean property gives true if the element still attached to the DOM and false if the element is removed from the DOM.

A set of strings, the strings will be stored in heap and the set will hold their reference. Ultimately, the memory consumption in this approach will depend on the size of the strings you are adding.

Now for a set of numbers, Small integers ranging from -2³¹ to 2³¹-1 will be directly stored in the Set consuming 8bytes, no extra heap allocation will be required. Numbers exceeding the range will be stored in the heap and the set will hold their references for that each number will consume 12bytes in heap. So, here also you get mostly a consistent size.

Conclusion Based on same size set for different data types

  • A Set just stores the reference of the items you are adding into it. So the difference is mainly due to the size of the item in heap.
  • If you have strings with small length, you can go with it.
  • If your use-case suites the element approach and handle the memory leak properly you may choose the set of elements approach.
  • A set of number can be a decent choice in most cases.
Sid
  • 451
  • 3
  • 9
  • 1
    In other words: the `Set` itself doesn't care what it's storing, each entry is a reference. Strings are not stored as (copied) values in the set. Any differences are due to numbers, strings, and DOM nodes having different sizes in memory (regardless of whether there are Set entries referring to them or not). DOM nodes are by far the biggest, but they're not on the JS heap, so you don't see them in a heap snapshot. For numbers in V8, it makes a big difference whether they're "small integers" or not. – jmrk May 07 '23 at 16:34
1

How much space an object reference, as well as a string or a number, takes is implementation specific to the JavaScript engine. But if we go from V8 (the enginge used in Chromium and Node.js):

A reference to an object, which is what you have in your el variable, takes 4 bytes.

See: https://v8.dev/blog/pointer-compression

But in general: What needs to be stored for an object reference is an address in memory.

A string consisting of 7 characters would take 20 bytes.

See: This formula: 12 + 4 * Math.ceil(n/4) found here how much memory do v8 take to store a string?

And as far I can tell a Number is stored as a 64-bit float (8 bytes).

So the string will consume the most memory (20 bytes), the number (8 bytes) and an object reference just 4 bytes. Go with object references, they also make life easy (unless you need serialization).

Thomas Frank
  • 1,404
  • 4
  • 10
  • 2
    References to objects take 4 bytes now (in Chrome, not in Node), see https://v8.dev/blog/pointer-compression. As far as the `Set` is concerned, a reference is a reference and they all have the same size. Of course, the referenced things (strings, numbers, DOM elements) have different size in memory. – jmrk May 07 '23 at 16:45
  • @jmrk Thanks! Great info! I updated my answer! The only thing I'm unsure about is Numbers. Do they always take 8 bytes or are there some nifty compression going on for small numbers? – Thomas Frank May 07 '23 at 16:49
  • 1
    Small integers ("smis") are stored right in the pointer and take no extra heap space at all. Other numbers take 12 bytes (4 bytes hidden class, 8 bytes payload). – jmrk May 07 '23 at 19:07