Computers have two ways to store data. Registers and Memory.
variables, objects, and everything in a computer program is an abstraction around these mechanisms.
L1 cache
L2 cache
L3 cache
RAM
Hard Disk
The Processor and the Registers
Memory
"Memory"
Although there are some limitations to this mindset, for now we are going to treat *all* of memory as one big bucket
Throughout the life-cycle of a program, data moves between memory and registers.
"Memory"
Because registers have limited storage, data that exceeds the limit must live in memory.
In JavaScript each integer is 64 bits. This array is therefore (at least) 5 times to large for a register.
var x = [1, 2, 3, 4, 5];
So our register gets a pointer to a memory address
var x = [1, 2, 3, 4, 5];
x = 0xFF019A
0xFF019A:
0: 1
1: 2
2: 3
3: 4
4: 5
x = 0xFF019A
0xFF019A:
0: 1
1: 2
2: 3
3: 4
4: 5
Hold up: Whats this?
This pointer is why Objects are called reference types. Our variable really holds a 64-bit pointer to a memory address
var x = [1, 2, 3, 4, 5];
x = 0xFF019A
0xFF019A:
0: 1
1: 2
2: 3
3: 4
4: 5
If we make a new variable and set it equal to x, this variable references the same memory location.
var x = [1, 2, 3, 4, 5];
var y = x;
x = 0xFF019A
0xFF019A:
0: 1
1: 2
2: 3
3: 4
4: 5
y = 0xFF019A
If we change one of the properties at that location both variables reflect the change.
x[0] = 100;
console.log(y[0]); // Prints 100
x = 0xFF019A
0xFF019A:
0: 100
1: 2
2: 3
3: 4
4: 5
y = 0xFF019A
But if we change what one of the variables points to then the modified variable points somewhere new.
y = [7,8,9]
console.log(y[0]); // Prints 7
console.log(x[0]); // Still prints 100
x = 0xFF019A
0xFF019A:
0: 100
1: 2
2: 3
3: 4
4: 5
y = 0xFF0EEE
0xFF0EEE:
0: 7
1: 8
2: 9
If all our registers are filled, even 64 bit primitive types may have to be stored into memory and fetched again when they are needed.
There is *a lot* of hardware and software that we rely on to handle this for us, and our mental model doesn't need to be perfect.
(and probably couldn't be without years of study in Computer Engineering, Computer Science, and Operating Systems)
Lets go here https://github.com/gSchool/computer-science-curriculum/blob/master/Unit-0/02-memory-diagrams.md
And look at some "memory diagrams" before we create some ourselves.
Stop when you get to "Prototypes" -- we'll discuss those later.
Take 10 minutes right now to read this
You all asked about Symbols, the new ES2016 (aka JavaScript 6) primitive type.
Now we have enough information to better understand Symbols.
var fooOne = new Symbol('foo');
var fooTwo = new Symbol('foo');
'foo' === 'foo' // this evaluates to true
fooOne === fooTwo; // What do you think this evaluates to?
// Why?
Learn by example
function fun1() {
var a = 1;
var b = 2;
return fun2(a, b);
}
function fun2(x, y) {
var c = x + y;
return c;
}
fun1();
We have the code to the left. Two functions are defined, then we call fun1.
At the "top level" we're on whats called the global frame. Before anything happens, it's empty.
// YOU ARE HERE
function fun1() {
var a = 1;
var b = 2;
return fun2(a, b);
}
function fun2(x, y) {
var c = x + y;
return c;
}
fun1();
Global Frame: returnTo: null |
Every stack frame knows where it was called from. The global stack frame is special in that it isn't called from anywhere.
After we execute the two function definitions, our stack looks like this
function fun1() {
var a = 1;
var b = 2;
return fun2(a, b);
}
function fun2(x, y) {
var c = x + y;
return c;
}
// YOU ARE HERE
fun1();
Global Frame: fun1: pointer to memory address fun2: pointer to memory address returnTo: null |
Calling fun1 adds a new frame
function fun1() {
// YOU ARE HERE
var a = 1;
var b = 2;
return fun2(a, b);
}
function fun2(x, y) {
var c = x + y;
return c;
}
fun1();
fun1 Frame: returnTo: Global Frame |
Global Frame: fun1: pointer to memory address fun2: pointer to memory address returnTo: null |
Local variables go onto the frame line by line
function fun1() {
var a = 1;
var b = 2;
// YOU ARE HERE
return fun2(a, b);
}
function fun2(x, y) {
var c = x + y;
return c;
}
fun1();
fun1 Frame: a: 1, b: 2 returnTo: Global Frame |
Global Frame: fun1: pointer to memory address fun2: pointer to memory address returnTo: null |
Calling fun2 adds a new frame, parameters are already on the stack when they are passed in.
function fun1() {
var a = 1;
var b = 2;
return fun2(a, b);
}
function fun2(x, y) {
// YOU ARE HERE
var c = x + y;
return c;
}
fun1();
fun2 Frame: x: 1, y:2 returnTo: fun1 frame |
fun1 Frame: a: 1, b: 2 returnTo: Global Frame |
Global Frame: fun1: pointer to memory address fun2: pointer to memory address returnTo: null |
c gets added after x+y is computed
function fun1() {
var a = 1;
var b = 2;
return fun2(a, b);
}
function fun2(x, y) {
var c = x + y;
// YOU ARE HERE
return c;
}
fun1();
fun2 Frame: c: 3, x: 1, y:2 returnTo: fun1 frame |
fun1 Frame: a: 1, b: 2 returnTo: Global Frame |
Global Frame: fun1: pointer to memory address fun2: pointer to memory address returnTo: null |
Return pops the top stack frame off the stack and sends execution back to the caller
function fun1() {
var a = 1;
var b = 2;
return fun2(a, b);
// YOU ARE ABOVE
}
function fun2(x, y) {
var c = x + y;
return c;
}
fun1();
fun1 Frame: a: 1, b: 2, tmpVal: 3 returnTo: Global Frame |
Global Frame: fun1: pointer to memory address fun2: pointer to memory address returnTo: null |
Return pops the top stack frame off the stack and sends execution back to the caller
function fun1() {
var a = 1;
var b = 2;
return fun2(a, b);
}
function fun2(x, y) {
var c = x + y;
debugger;
return c;
}
fun1(); // Returning to here now
Global Frame: fun1: pointer to memory address fun2: pointer to memory address tmpVal: 3 returnTo: null |
After this, the program terminates.
function fun1() {
var a = {
p1: 1,
p2: "text",
};
return a;
}
var b = fun1();
debugger;
... somewhere in the heap ...
p1: a
p2: "text"
The Stack will contain the value for b -- which is a pointer to this data somewhere in the heap!
Because the heap doesn't have a specific pattern for memory allocation, we have to do more work to "free" the memory allocated.
In older languages, this was done manually by programmers!
char *str;
/* Initial memory allocation */
str = (char *) malloc(15);
/* Reallocating memory */
str = (char *) realloc(str, 25);
/* Free the space */
free(str);
In modern languages a separate program called "the garbage collector" periodically searches for objects that no longer have any pointers pointing at them
function fun1() {
var a = {
p1: 1,
p2: "text",
};
return a;
}
console.log(fun1());
// At this point there is
// no way to access 'a'
After the console.log statement completes, there is no reference to the object we called 'a'. The Garbage Collector will find it, and free it's space on the heap.
function fun1() {
var a = {
p1: 1,
p2: "text",
};
return a;
}
console.log(fun1());
... somewhere in the heap ...
p1: a
p2: "text"
After the console.log statement completes, there is no reference to the object we called 'a'. The Garbage Collector will find it, and free it's space on the heap.
function fun1() {
var a = {
p1: 1,
p2: "text",
};
return a;
}
console.log(fun1());
... somewhere in the heap ...