Writing is not easy, without the permission of the author forbid to reprint in any form! If you think the article is good, welcome to follow, like and share! Continue to share technical blog posts, follow the wechat public account 👉🏻 front-end LeBron

Why is garbage collection needed

  • In C/C++, tracking memory usage and managing memory can be a burden for developers
    • JavaScript is a language that uses a garbage collection mechanism, which means that the execution environment is responsible for managing memory while the code executes, taking this burden off the developer
    • Automatic memory management is used to allocate memory and recycle resources
    • The basic idea is simple: determine which variable is no longer used and free its memory
    • This process is periodic, meaning that the garbage collection program runs once in a while
  • Memory for objects, strings, and objects in JS is not fixed and is allocated dynamically only when it is really needed
    • This memory needs to be freed for reuse when it is not in use, or it will crash when the computer runs out of available memory
  • In the history of browser garbage collection, there are
    • Reference counting method
    • Mark clearance

Reference counting method

Train of thought

  • Variables simply refer to values
  • When a variable references this value, the number of references is +1
  • When a reference to this variable is overwritten or cleared, the number of references is -1
  • When the number of references is zero, this memory can be safely freed.
let arr = [1.0.1]   // The memory block [1, 0, 1] is referenced by arR at 1 times
arr = [0.1.0]  // Memory references for [1, 0, 1] are freed with 0
                 // Memory [0, 1, 0] is referenced by arR for 1 time
const tmp = arr  // Memory [0, 1, 0] is referenced by TMP for 2 times
Copy the code

Circular reference problem

Netscape Navigator 3.0

  • In this example, the properties of ObjectA and ObjectB refer to each other, respectively
  • After this function is executed, the number of Object references does not become 0, affecting normal GC.
  • If executed multiple times, it will cause a serious memory leak.
  • This problem does not occur with the tag removal algorithm.
function Example(){

    let ObjectA = new Object(a);let ObjectB = new Object(a); ObjectA.p = ObjectB; ObjectB.p = ObjectA; } Example();Copy the code
  • Solution: Point to null at the end of the function
ObjectA = null;
ObjectB = null;
Copy the code

Mark clearance

To solve the memory leak problem caused by circular references, Netscape Navigator 4.0 began to use tag cleaning

By 2008, Internet Explorer, Firefox, Opera, Chrome, and Safari have all adopted tag cleaning (or variations of it) in their JavaScript implementations, with differences in how often they run garbage collection.

Train of thought

  • Mark the variable as it enters the execution context
  • The variable is also marked “away” when it leaves the execution context
    • This variable cannot be accessed from now on
    • Memory is freed at the next garbage collection
function Example(n){
    const a = 1, b = 2, c = 3;
    return n * a * b * c;
}
// mark Example to enter the execution context

const n = 1;  // flag n to enter the execution context
Example(n);   // flags a,b,c to enter the execution context
console.log(n); // Mark a, B, c out of execution context, waiting for garbage collection
Copy the code

Const and let declarations improve performance

  • Const and let not only help improve code style, but also improve garbage collection performance
  • Const and let enable JS to have block-level scope, and the garbage collector gets involved earlier when the block-level scope ends before the function scope
  • The performance of garbage collection is improved by collecting the reclaimed memory as early as possible

V8 engine garbage collection

The garbage collection of V8 engine adopts mark removal method and generation collection method

It is divided into Cenozoic and old generation

The new generation

The Scavenge algorithm is used for new generation garbage recycling

A small amount of memory allocated to common and newly allocated memory

  • Memory size

    • 32-bit system 16M memory
    • 64-bit system 32M memory
  • partition

    • The new generation of memory is divided into the following two areas, memory accounted for half
    • From space
    • To space
  • run

    • The only thing that actually runs is From space
    • To space is idle
  • Scavenge algorithm

    • Garbage collection begins when From space memory usage is about to reach its maximum, marking unreachable objects in From space
    • Copy an unmarked object From space To To space.
      • Fixed memory fragmentation (discontinuous memory space)
      • It’s like swapping space for time.
    • Then empty “From space” and leave it idle, which is called “To space”.
  • New Generation -> Old generation

    • The new generation stores a small amount of newly allocated memory that will be allocated to the old generation if one of the following conditions is met
      • Memory size up to 25% of From space
      • Experienced a cycle From space <-> To space

The old generation

The old generation used mark-sweep and Mark-Compact

It usually holds large chunks of memory and chunks allocated from the new generation

  • Memory size
    • The 32-bit system is about 700 MB
    • About 1.4GB for 64-bit system
  • partition
    • Old Object Space
      • Literal old generation, store is the memory allocated by the new generation.
    • Large Object Space
      • Store large memory that is not fit for other areas, basically more than 1M
    • Map Space
      • Stores the mapping of storage objects
    • Code Space
      • Store compiled code
  • The recycling process
    • Classification of markers (tricolor markers)
      • Unscanned, recyclable, referred to belowClass 1
      • Scanning, not recyclable, referred to below2 class
      • The scan is complete and cannot be recycledThree kinds of
    • traverse
      • Use depth-first traversal to traverse each object.
      • First mark all non-root objects asClass 1And then perform depth-first traversal.
      • The traversal pushes the object onto the stack. The object is marked as2 class.
      • The traversal completes the object removal from the stack, and the object is marked asThree kinds of.
      • The whole process continues until the stack is empty
    • Mark-sweep
      • Once the tag is complete, it will be marked asClass 1Object to free memory
    • Mark-compact
      • After garbage collection is complete, the memory space is discontinuous.
      • This can easily lead to a problem of not being able to allocate large memory Spaces, triggering garbage collection.
      • As a result, there is a Mark-Compact step to collate unreclaimed memory blocks into contiguous memory space.
      • Frequently triggering garbage collection can affect engine performance, and mark-Compact can also be triggered preferentially when memory space is low

Garbage collection optimization

  • Incremental tag
    • If you do garbage collection for a concentrated period of time, the new generation is fine, but the old generation can cause lag if it iterates over larger objects.
    • Incremental markup: Alternating garbage collector and application logic, similar in idea to Time Slicing
  • Parallel recovery
    • In the process of garbage collection, several auxiliary threads are opened to improve garbage collection efficiency.
  • Concurrent collector
    • During the execution of the logical program, several auxiliary threads are opened for garbage collection to clean up the memory that has no logical relationship with the main thread.

Memory Leak Scenario

The global variable

// exm1
function Example(){
    exm = 'LeBron'   
}

// exm2
function Example(){
    this.exm = 'LeBron'
}
Example()
Copy the code

Uncleared timer

const timer = setInterval(() = > {
    / /...
}, 1000)

// clearInterval(timer)
Copy the code

closure

function debounce(fn, time) {
  let timeout = null; 
  return function () {
    if (timeout) {
      clearTimeout(timeout);
    }

    timeout = setTimeout(() = > {
      fn.apply(this.arguments);
    }, time);
  };
}

const fn = debounce(handler, 1000); // fn references timeout
Copy the code

Uncleared REFERENCES to DOM elements

const element = {
    // The DOM element is referenced here
    button:document.getElementById('LeBron'),
    select:document.getElementById('select')}document.body.removeChild(document.getElementById('LeBron'))
Copy the code

How do I detect memory leaks

This is easy to do with the developer tool Performance that comes with the browser

  • steps
    • F12 Open developer tools
    • Select the Performance toolbar
    • Check screen capture and Memory
    • I’m gonna hit start recording
    • End the recording after some time
  • The results of
    • Heap memory is allocated and freed periodically
    • There is a memory leak if the min value of heap memory is gradually increasing

Optimize memory usage

  1. Try not to define functions in the for loop
// exm
const fn = (idx) = > {
    return idx * 2;
}

function Example(){
    for(let i=0; i<1000; i++){//const fn = (idx) => {
        // return idx * 2;
        // }
        constres = fn(i); }}Copy the code
  1. Try not to define objects in the for loop
function Example() {
  const obj = {};
  let res = "";
  for (let i = 0; i < 1000; i++) {
    // const obj = {
    // a: i,
    // b: i * 2,
    // c: i * 3,
    // };
    obj.a = i;
    obj.b = i * 2;
    obj.c = i * 3;
    res += JSON.stringify(obj);
  }
  return res
}
Copy the code
  1. Empty array
arr = [0.1.2]
arr.length = 0; // Empty the array, the array type remains unchanged
// arr = [] // Reapply an empty array object memory
Copy the code

  • Nuggets: Front-end LeBron

  • Zhihu: Front-end LeBron

  • Continue to share technical blog posts, follow the wechat public account 👉🏻 front-end LeBron