0% found this document useful (0 votes)
9 views15 pages

Variables and Values

Uploaded by

Vu Hoai Nam
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
9 views15 pages

Variables and Values

Uploaded by

Vu Hoai Nam
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 15

VARIABLES AND VALUES

Overview
When we start learning to program, the first things we have to understand are variables
and values. But I see that many people get confused with these basic concepts. There are
lots of FALSE statements that variables keep what we assigned in them like a box or
primitive values are stored in stacks,…. The thing is, lots of developers use variables
without really knowing how they work. Today, let's talk about what variables and values
really are, and correct misconceptions by peeking under the hood at the JavaScript
language implementation to see how values are stored in memory.
Mental model for variables:

Imagine your code as a busy planet filled with instructions. In the world of JavaScript,
values are like floating things in space.
Think of primitives as faraway stars—they're there, but you can't touch or change them.

Now, objects are like floating ships nearby. They have connections to other ships or
primitive planets.

Remember that: Primitives are like natural and unchangeable things, kind of like forces
of nature. Objects are more like things we make and can control.

Enter variables—they're like the people on your code planet. Their job is to connect with
and control the ships or keep an eye on the primitive planets.

I won't get too deep into this idea, but seeing it in this way might make understanding
JavaScript variables and values a bit easier.
You might be thinking: why do we have to add extra pointer indirections between values
and variables/object properties? This (mostly) has to do with the nature of the language
being dynamically typed. In a dynamically typed programming language, the type checks
are performed at runtime.
However JavaScript variables can hold any type of values at runtime. Therefore, the
types cannot be associated with a variable but with the underlying value
pointed/referenced by a variable. To achieve that, we need a uniform memory
representation for JavaScript variables - pointers. And the real values are allocated
somewhere else on the heap (dynamic memory), containing metadata such as the type
and the size of the value, pointed by those pointers.
JavaScript cannot do pass-by-reference

But there are contrary opinions misunderstand that JavaScript objects are assed-by-
references, but that's not quite right. JavaScript doesn't actually do pass-by-reference.
When you store an object in a variable, it's not a direct alias of the object itself but a copy
of the address where the object lives in the heap.
Now, if you give that variable a new value, it doesn't replace the original object. It just
points to a different place in memory. But because it still has the address, it can access
and change the contents (like properties) of the original object
Primitive values are also allocated on the heap
Another claiming you can read on resources online that JavaScript primitive values are
allocated on the stack while objects are allocated on the heap. This idea is false, at least
this is not how the language is implemented in the majority of JavaScript engines.
Contrary to common belief, primitive values are also allocated on the heap, just like
objects. To prove this statement, let’s inspect one of the most popular JavaScript engines
– V8.
“JavaScript values in V8 are represented as objects and allocated on the V8 heap, no
matter if they are objects, arrays, numbers or strings.” - v8 blog

First, use command node --v8-options | grep -B0 -A1 stack-size to get the
default size of stack in V8. My result is 984kB.

We use this script to inspect the memory in heap before and after creation of 10MB string

The size of the heap memory used before we created the string was 4.01 MB
After I created a string of a size of 10 MB, the heap memory used increased to 14.01 MB

The difference is exact the size of string we created. See the stack size we printed out
before, it was only 984kB - there is no way the stack can store such a string.

When debugging v8 on small string, we can see that string are located in Old Space of Heap memory.

String internal
A quick question: If we assign 2 variables to the same string. Does it result in the
duplication of the string in memory, or end up with 2 strings allocated on the heap?
The answer to this question depends on the way you create strings:
In order to efficiently process strings, the V8 engine maintains a string constant pool.
Strings are stored in the string constant pool.
name1 refers to a string in string constant pool directly while name2 refers to an object in
heap.
So what is the difference?
If we add 2 variables to the code:

The memory allocation will be:

We can find a funny truth: name1 and name3 point to the same location,
while name2 and name4 point to two different objects.
Let’s inspect details in chrome webtool:

This code will create an array arr of length 10000 of "bytefish" and another array of
length 10000 of new String(“bytefish”)
When inspect in chrome devtools

Although there are 10,000 elements in the array, they all have the same address
@271085. This verifies the existence of the string constant pool we mentioned earlier.

About new String(“bytefish”), new object will be created each time we declare new one,
increasing memory assumption.
Oddballs
There are a special subset of primitive values called Oddball in V8.

They are pre-allocated on the heap by V8 before the first line of your script runs - it
doesn’t matter if your JavaScript program actually uses them down the road or not.
They are always reused - there is only one value of each Oddball type.

Take a memory snap shot of above snippet, we get:


You see? Each Oddball type only has the same memory location on the heap even though
the values are pointed by different objects' properties.

When we are creating JavaScript variables that "have" Oddball values, we should think as
if they were "summoned" in our JavaScript program - we cannot create or destroy them.

Number
All numbers in JavaScript are represented as floating-point values. JavaScript represents
numbers using the 64-bit floating-point format (like double in C)

with sign bit to mark negative/positive

exponent (bias 1023) to represent fractional parts

So min/max number of type number is +-2^53-1 (stored in


Number.MAX_SAFE_INTEGER),
That’s what the specs tell us. But in our code, we mainly deal with integers, so it will be
wasteful if we present them as floats. V8 is highly optimized so it will decide whether a
number is stored on stack or heap base on its value. If an integer is small enough to be
encoded inside a pointer (31bit integer), it could store on stack.

With float number, it will be a map to Heap Number Object on heap.


But how small is Small Integer (smi) and how v8 engine differentiate between smi and
pointer?
V8 uses tagged pointers to do that. Because of how memory is aligned, pointers usually
point to memory locations that are multiples of 4(32 bit/8) or 8 bytes(64bit/8). That
means that the last 2–3 bits of a pointer will always be 0 and will never be used. V8 will
make use of that and will encode some type information inside the last bit. You can read
more at: Pointer compression
32 bits:

64 bits:

For pointers, V8 will always set the last bit to 1. If that bit is 1, it means we are dealing
with a pointer. That also means that before using that pointer, we need to clear that last
bit (set it to 0) because it was set to 1 just to mark that variable as a pointer.
For small integers (SMI), the last bit will be set to 0. That means that small integers are
31bit long on both 32 bit and 64 bit systems. ([-230, 230-1])
So technically, a smi can exist on the stack since they don’t need additional storage
allocated on the heap, depending how the variables are declared:

- const a = 3 could be on stack


- var a = 3 will be on heap because it becomes property of global object

Another complication about numbers is, unlike other types of primitive values, they
might not get reused:

- For smis, they are encoded as recognizably invalid pointers, which don't point to
anything, so the whole concept of "reusing" doesn't really apply to them.
- For HeapNumbers (numbers that are not considered smis) can and do get reused,
but when they are pointed by object's properties, it becomes a mutable
HeapNumber, which allows updating the value without allocating a new
HeapNumber every time. If you simply had a function f() { return 12.5; }, it would
actually return the same reused HeapNumber every time it's called.

So now let me revise the statements we have concluded today for completeness:
• JavaScript objects are not passed by reference but involve copying the object's
memory address
• All JavaScript values are allocated on the heap accessed by pointers no matter if
they are objects, arrays, strings or numbers (except for small integers (smi) in V8
due to pointer tagging).
• Primitive values are (mostly) reused

Reading materials:
https://v8.dev/blog/react-cliff
https://v8.dev/blog/pointer-compression
https://docs.google.com/document/d/11T2CRex9hXxoJwbYqVQ32yIPMh0uouUZLdyrtmMoL44/edit#he
ading=h.jvrqdo9eoczl

You might also like