A, memory,

1. What is memory?

Memory is one of the most important parts in computer. It is the bridge between external memory and CPU. All programs in a computer are run in memory, so the performance of memory has a great impact on the computer.

2. Memory life cycle

Regardless of programming language, the memory life cycle is divided into three main phases:

  1. Allocate memory: Memory allocated by the operating system for use by programs
  2. Using memory: After a program has acquired memory allocated by the operating system, read and write operations occur in memory
  3. Free memory: When a program finishes using memory, it frees it up for use by other programs. In JavaScript, there is a garbage collection mechanism that automatically frees memory.

Memory allocation in JavaScript

In the daily work of front-end development, variables are declared and assigned almost every day, and these variables end up in memory, so it’s important to understand how memory is allocated in JavaScript.

1. Two data types in JavaScript

JavaScript has two types of data: basic and reference data types

  1. Basic data types: number, string, Boolean, undefined, NULL, symbol
  2. Reference data types: Array, Function, Object, Date, Math, RegExp, etc
2. Three data structures in JavaScript

There are three types of data structures in JavaScript: heap, stack, and queue.

When a program is running, it needs memory to store data. Generally speaking, the system divides two different memory Spaces: one is called a heap and the other is called a stack. There is no strict distinction between stack and heap memory in JavaScript.

  • Heap has no structure, most of the time is regarded as a tree structure, data can be arbitrarily accessed, it is used to store complex data types (reference types), such as array objects, object objects, etc..
  • The stack is structured, and each block is accessed in a certain order, which is characterized by advanced and then out, and then in and first out. The main storage in the stack is the value of basic types of variables and the address pointing to the array or object in the heap. The size and lifetime of data in the stack must be determined. In addition, the size of each block is clearly known, so the stack is addressing faster than the heap

  • A queue is a first-in, first-out (FIFO) data structure.

3. JavaScript variable declarations and assignments for two data types
  • Variable declarations and assignments for primitive data types

First, define a variable num and assign it a value of 1.


let num = 1;

Copy the code

When the JavaScript engine executes this line of code, it does something like this:

  1. Create a unique identifier for the variable num that maps to address A1 in stack memory.
  2. Assign it an address A1 in stack memory.
  3. Stores the value 1 to the assigned address.

As shown in the figure:

The value of num is usually said to be equal to 1, but strictly speaking, the value of num is equal to the memory address in the stack where the corresponding value is stored (A1 in the figure). Next we create a new variable new_num and assign num to it:


let new_num = num;

Copy the code

After the above assignment, it is usually said that the value of new_num is 1, which also strictly means that new_num and num refer to the same memory address A1, as shown in the following figure:

What happens if we increment new_num by 1?


new_num = new_num + 1;

Copy the code

Since the basic data types in JS are immutable, when the value of new_num changes to 2, JS will allocate a new address in memory, store 2 as its value, and new_num will point to the new address. As shown in the figure below

  • Variable declarations and assignments that reference data types

Let’s define an array arR;

Let arr = [1, 2, 3];Copy the code

When the JavaScript engine executes this line of code, it does something like this:

  1. Create a unique identifier for the variable ARr that maps to address A3 in stack memory.
  2. Assign it an address A3 in stack memory.
  3. Stack memory stores the value x023 of the memory address allocated in the heap.
  4. Stores an empty array of allocated values [1,2,3] in the heap.

Next we create a new array and assign arR to it


let new_arr = arr;

Copy the code

Assignment works in the same way as the base data memory, creating a unique identifier for a variable and pointing to the same address A3 in stack memory as arR. As is shown in

And then we change the value of the first term in arR, what happens?


let arr[0]=5;

Copy the code

We changed the value of the first entry of the ARR, only in the memory heap, changing the pointing value of the identifier 0 under the address x023. The identifiers ARr and new_arr point to the same A3 address in the memory stack. The reference address in the corresponding heap is still X023. Therefore, when we change the value of arr, we also change the value of new_arr, so that the current values of both arr and new_arr become [5,2,3]. As shown in the figure:

4. Principle of deep and shallow copy of reference type

Now that we know how data is stored in memory, we can easily understand how deep and shallow copy in JS works.

What’s the difference between a deep copy and a shallow copy?

  • Shallow copy: A shallow copy copies only the outermost properties of an object, that is, the data of its basic type. For the reference type data of an object, a shallow copy copies only its reference, pointing to the same address.
  • Deep copy: Deep copy does not copy references of reference types, but layers until the pointing value is the underlying data type.

It doesn’t look very clear, but let’s visualize it.

First, let’s define an object, obj.


let obj = { a:{name:"anna",age:10},b:{name:"baby",age:40,work:{worker_age:10,company:"acb"}},id:0};

Copy the code

First of all, obj is pointing to A in the stack. The reference address in the heap is 0x001. The 0x001 heap then stores two reference types of data, a and B, as well as the data ID of the underlying data type. Their directions are shown in the following figure:

From the above flowchart we can see how a complex data type is stored in memory. So let’s take a look at how this data is stored in memory for deep and shallow copy.

Now let’s make a shallow copy of the data

let copy_boj = {... obj};Copy the code

We create a new space in the heap and copy the data at 0x001 into it. The current data points to the following figure:

In shallow copy, we only copy the OBj object once. Now the data in obj is pointing exactly the same as the data in copy_obj.

Now what happens if we change the ID of OBj?


obj.id = 1;

Copy the code

At this point, since the ID of obj is an underlying data type, the value corresponding to the ID of obj becomes 1. And the id of copy_obj, it’s still going to be 0. If you don’t understand anything, go back to variable declarations and assignments for primitive data types.

So what happens if we change the age in A to 11?


obj.a.age = 11;

Copy the code

At this point, we are changing the value of age in 0x111. Since the a in obj and the A in copy_obj both point to 0x111. Therefore, when the age in 0x111 is modified. Both obj.a.age and copy_obj.a.age have been changed to 11.

5. The let and const
  • Let: Used to define variables.
  • Cosnt: Used to define constants.

In general, we should use const as often as possible, and only use let when we know a variable will change. How do we understand change?

Let’s take a look at the following cases.

Const name = "Bob ", num_arr = [1,2,3];Copy the code

What happens if we try to change the value of name?


name = "baby";   // Uncaught TypeError: invalid assignment to const 'name' 

Copy the code

Error message, constant cannot be modified. Because when we assign a new value to name, the address in the memory space referred to by the identifier name will change.

What happens if you change the value of an item in new_arr?

num_arr[0] = 4; // num_arr = [4,2,3].Copy the code

As you can see, the num_arr data has been successfully modified. For reference type data, we store a reference address, although we change the value of the first item in the num_arr array. But num_arr, the identifier pointing to the memory address, has not changed. As shown in the figure:

What if we just reassign new_arr?

Num_arr = (three, four, five); // invalid assignment to const 'num_arr'Copy the code

Now that we have reassigned num_arr, num_arr will no longer refer to the same address. Therefore, the modification is not successful. As is shown in

As you can see, changing is actually changing the memory address. Let allows memory addresses to be changed. Const does not allow memory addresses to change. Is it now easier to understand when a const will succeed and when an error will be reported?

Now that the reference to num_arr has changed, what happens to the object that was originally referenced? Then we have to mention the garbage collection mechanism in JS.

Three, memory space management

JavaScript has an automatic garbage collection mechanism, so how does this automatic garbage collection mechanism work? Find values that are no longer in use and free up memory. As shown in the figure:

Assume that in our current program, only one identifier, num_arr, is referenced. We use green to represent the data num_arr is currently referencing. Data that is not currently used is represented by a red box. Due to the contents of the red box, it is no longer used. Therefore, the garbage collection mechanism automatically reclaims the data in the red box after a period of time, freeing up its memory.

What are the common garbage collection mechanisms in JS?

  • Mark clearance

    • The most common garbage collection method in JS is tag cleanup. When a variable enters the execution environment, it is marked as “enter environment”. When a variable leaves the environment, it is marked “out of the environment.” The garbage collection mechanism takes the roots and marks them, accesses and marks all references from them, then accesses those objects and marks their references, and so on until they are unreachable. Then the garbage collection mechanism will delete the unreachable ones, and cannot delete the ones that enter the execution environment
  • Reference counting method

    • When a variable is declared and a reference type is assigned to the variable, the number of references to the value is 1. Conversely, if the variable containing a reference to that value obtains another value, the number of references to that value is reduced by one. When the number of references becomes zero, there is no way to access the value, and the garbage collection mechanism clears the object

In a local scope, when the function is finished executing, there is no need for local variables to exist (except for closures), so it is easy for the garbage collector to make judgments and reclaim. However, it is difficult to determine when global variables need to free memory space, so in principle we should avoid using global variables in our development. If it needs to be used, try to set it to NULL after it is used. Manually release its memory.