How much memory do Srings & Arrays consume in JavaScript?

69 Views Asked by At

I am trying to understand memory used by Strings & Arrays. As per this helpful question: How many bytes in a JavaScript string?

Blob is a great way of checking byte size of Strings: new Blob(['a']).size -> 1 byte

But Strings are encoded UTF-16 in JavaScript which uses minimum of 2 bytes. How does Blob return 1?

Furthermore, -----

const x = 200;
const y = 200;

const changes = []

for (let i=0;i<y;i++) {
    let subArr = []
    for (let j=0;j<x;j++) {
        subArr[j]= new Uint8Array(1)
    }
    changes[i]=subArr
}
console.log(new Blob(changes).size)

The array above consumes 79800 instead of 40000 (200*200 of Uint8Array(1)).

  1. Why does the array above consume double (79800) of what I expect (40000)? Also, why is the first index (0) interpreted as 1 byte and the following ones are 2 bytes ? Why is that?

'

for (let i=0;i<y;i++) {
   changes[i] = new Array(x).fill(new Uint8Array(1))
}
  1. If I fill the array using the above, it still consumes 79800. Why is that? As pointed out in comments, its the same Uint8Array object that gets filled x times.
1

There are 1 best solutions below

10
Sergiu Paraschiv On BEST ANSWER

Blob uses UTF-8 to represent strings. The minimum byte size for UTF-8 is 1 and character 'a' can be represented in UTF-8 using a single byte. A two-byte UTF-8 character ('Ђ' for example) returns 2, and something even longer like complex emoji ('') returns 4.

Regarding the 79800 vs 40000 bytes example: you are not building an array of 40000 bytes and passing it to Blob. You are building an array of arrays of bytes. The "leaf" nodes of these arrays of arrays are indeed 40000 bytes, but that's not what you use to build the Blob...

The documentation is a bit vague, but helpful after you do some experimenting.

"The content of the blob consists of the concatenation of the values given in the parameter array."

The concatenation of the values. What does that mean? Concatenation is an operation on arrays, terminology mostly used to mean "join two strings". Well, let's do some experimenting:

await new Blob('a').text() resolves with 'a', await new Blob([new Uint8Array(1)]).text() resolves with '\x00', await new Blob([[new Uint8Array(1)]]).text(), which is closer to your example, resolves with '0'. Huh...that makes perfect sense, since new Uint8Array(1).toString() is '0' too.

await new Blob([[new Uint8Array(1),new Uint8Array(1)]]).text() resolves to '0,0', which also makes sense because [new Uint8Array(1),new Uint8Array(1)].toString() is '0,0' too.

This last one is the explanation basically. When you pass things which are not strings to Blob it automatically turns them to strings "for you".

And arrays turned to strings take up more than just the string representations of their elements because we also get commas between them.

Going back to your example again, you are passing 200 arrays of 200 Uint8Array(1) instances to Blob. Each one of the "inner" arrays is turned to a String, meaning it's 200 '0' characters plus 199 ',' characters. And (200 + 199) * 200 is, you guessed it, 79800!

The main lesson here is: whatever you pass to Blob is "strigified" first.