preface

  • JavaScript is an automatic garbage collection language, and “we” cannot actively control the V8 garbage collector to do the corresponding garbage collection

  • This article introduces V8’s garbage collection mechanism in the following sections

    1. Introduce the generation hypothesis and different garbage collection algorithms

    MDN- Memory Management Understands JavaScript memory management through a garbage collection mechanism

    1. Stack and heap structure

    Dev /blog/orinoc…

    1. Which garbage collection algorithms V8 uses in different areas of the heap
    2. How to understand programs, processes, threads, concurrency, parallelism, high concurrency?

    Recommend an article, this is not introduced in detail: www.zhihu.com/question/30…

    1. What are the optimization strategies for garbage collection? And V8 it took what optimization strategy

The Generational Hypothesis

  1. Most of the subjects are dead and alive
  2. The undead live longer

Garbage collection algorithm

  • Garbage collection process
1. Somehow distinguish between live objects and garbage data 2. Reclaim garbage data 3. Memory defragmentation (optional)Copy the code

Reference counting method

  • Reclaim objects that are not referenced

Memory leaks occur when circular references are encountered

  • Source of case
    function example () {
        var obj1 = {
            property1: {
                subproperty: 20}};var obj2 = obj1.property1;
        obj2.property1 = obj1;
        return 'some random text';
    }
    example();
Copy the code
  • Example before the function is called

  • After the example function is called, we can’t recycle it as garbage because the two objects refer to each other, but we’re actually done calling the function, and we’re running out of memory

Mark-sweep

  • Because reference counting method may have the problems described above, it extends the Mark-sweep algorithm, which is mainly a reachable algorithm.

That is, along GC Root (global object…) BFS traversal scans can access data as live objects, otherwise objects that cannot be queried from GC root are cleared

  • photo

  • Source of case
   function marry (man,woman) {
       woman.husband = man;
       man.wife = woman;
       return {
           father: man;
           mother: woman;
       };
   }
   
   let family = marry({
       name: "John"}, {name: "Ann"
   })
Copy the code

    delete family.father
    delete family.mother.husband
Copy the code

Mark-compact

The marking part operates in the same way as Mark-sweep, but then all reachable objects are adjusted to one end and memory is cleared beyond this end (the adjusted end is retained, which is full of reachable objects, and memory is now continuous).

Scavenge algorithm, a variant of the half-space collector

Half-space collector: Divide the region into two equal regions from space and to space, and when the from space area is full, orderly move the living objects to the to space (to prevent memory fragmentation), swap roles, The Scavenge algorithm identifies young generation(nursery and intermediate) and old generation, as illustrated below, the insane

  • photo

  • For the first time the GC

  • The second time the GC

Stack and heap data structures

  • photo

  • Function execution stack
    function main() {
        func1();
    }
    function func1() {
        func2();
        func3();
    }
    function func2() {};
    function func3() {};
    main();
Copy the code

  • photo

  • Stack and heap memory usage during code execution is as follows
    class Employee {
        constructor(name, salary, sales) {
            this.name = name;
            this.salary = salary;
            this.sales = sales; }}const BONUS_PERCENTAGE = 10;

    function getBonusPercentage (salary) {
        const percentage = (salary * BONUS_PERCENTAGE) / 100;
        return percentage;
    }

    function findEmployeeBonus (salary, noOfSales) {
        const bonusPercentage = getBonusPercentage(salary);
        const bonus = bonusPercentage * noOfSales;
        return bonus;
    }

    let john = new Employee("John".5000.5);
    john.bonus = findEmployeeBonus(john.salary, john.sales);
    console.log(john.bonus);
Copy the code
  • photo

V8 garbage collection mechanism

Explain V8’s two different garbage collectors

  • How is junk data generated?
    window.text = new Object(a);window.text.a = new Array(100);
    window.text.a = new Object(a);Copy the code

Garbage data is data in the heap that can be overwritten by a stack offset pointer, without the need for a special garbage collector

  • V8 garbage collection is divided into a secondary garbage collector and a primary garbage collector
    • The secondary garbage collector deals with the new generation, using the Scavenge garbage recycling algorithm
    • The main garbage collector handles the old generation, using a combination of mark-sweep and Mark-Compact garbage collection strategies

    If memory fragmentation is excessive, mark-Compact is used to eliminate memory fragmentation

case

  • Analyze what garbage data is generated by the following code
    function strToArray (str) {
      const len = str.length; / / 10
      let arr = new Array(str.length);

      for(let i = 0; i < len; ++i) {
        arr[i] = str.charCodeAt(i); // Convert to ASCII for storage
      }
      return arr; // This return is optional...
    }

    function foo () {
      let i = 0;
      let str = "test V8 GC";

      while (i ++ < 1e5) {
        strToArray(str);
      }
    }

    foo();
Copy the code
  • What garbage data is generated

    Every time foo is executed, the while loop generates junk data

StrToArray Array arR generated from the STR argument after the call

  • How does V8’s garbage collector recover this garbage data
    1.First, enter work in the freshman area    2.Apply the Scavenge algorithm to idle when the work is exploiture    3.The work area is then clearedNote: Because every garbage data generated above cannot be retrieved from the GC Root trigger, it can be flushed out after the first Scavenge algorithmCopy the code

  • Optimize this code from the perspective of memory space and main thread
    1.Since each loop call to strToArray requests a new array, we can create a new array in Foo and then call strToArray to pass it in(js passing is passing values), so that when foo is called, it only generates 1 junk data 2. In order to optimize the execution stack, if you call foo into the loop, each time you call strToArr, there will be two function contexts in the execution stack. If you write the strToArray logic into the foo loop, * Tail-call optimizes the stack for recursive functions to prevent stack explosion, but browsers don't support it nowCopy the code
  • Optimize code behind stack and heap execution
    function foo () {
      let i = 0;
      let str = "test V8 GC";
      const len = str.length; / / 10
      let arr = new Array(str.length);

      while (i ++ < 1e5) {
        for(let i = 0; i < len; ++i) {
          arr[i] = str.charCodeAt(i); // Convert to ASCII for storage
        }
      }
    }

    foo();
Copy the code

Optimization strategies for garbage collection

Stop The World

JavaScript is single-threaded, interspersed with the garbage collection operation on the basis of the original JS execution. If the garbage collection operation takes a long time, then the user will obviously feel that the page is stuck

For example, the page is executing a JavaScript animation that will not execute for 200 milliseconds because the garbage collector is workingCopy the code

Parallel collection

Garbage collection begins at GC time

Incremental recycle

  • With large objects (Windows, DOM, etc.), it still takes a long time to perform old-generation garbage collection through a parallel collection strategy, so V8 introduced an incremental collection strategy. Perform a small part of the complete garbage collection process at a time

  • Implementation difficulties

1. Do I need to record where garbage collection is executed when it is paused and restart before it can continue from the record point

2. The JavaScript code executed during the garbage collection pause changes the marked garbage data, so the garbage collector needs to be able to handle it correctly when it restarts

  • Before the incremental algorithm was introduced, V8 used black and white to separate data in Mark-Sweep’s Mark, which presented a problem: if JavaScript executed after a pause changed garbage data that had already been marked, the garbage collector would not be able to process it properly when it was restarted

    • Initially all data is white
    • Mark phase: Starting from GC root, all accessible data is marked black and black is the live data
    • Sweep phase: The garbage collector will collect white garbage data
  • Therefore, a variant of the three-color notation is implemented to solve this problem

    *Initially: The black set is empty, the gray set is the set of objects referenced directly from the root, and the white set contains other objectsThree-color marking algorithm flow: 1. Select an object from the gray set, and then move it to the black set 2. Moved the reference object of each white grey group 3. Repeat steps 1 and 2, until the gray sets empty * all cannot arrive from the root object will be added to the white in the collection, and object can only move from white to gray, from gray to black, the algorithm may appear black object reference grey object, grey object reference object, white It is impossible for a black object to reference a white object (tricolor invariant)Copy the code

  • V8 uses strong tricolor invariance: when the black node points to the white node, it passesWrite barrier mechanismTo makeThe white node turns gray
  • The grey set is empty -> the main thread will do garbage collection -> the main thread will rescan GC root to find as many white nodes as possible, and the marking of white nodes is done in parallel by the helper thread
1. If F is disconnected and the tag list is empty 2. Main thread completes garbage collection 3. The main thread resends GC root, and if there are any unscanned nodes in the Black set, it transfers them from the Black set to the White set (using the same BFS for comparison).Copy the code

Concurrent collection

This approach can make the host thread execute the JavaScript code completely, thus avoiding the full wait, resulting in a poor user experience, but it is difficult to implement

  • The helper thread of garbage collection and the main JS thread modify the same object at the same time, and then need to add read/write locking mechanism
  • The contents of the heap can change at any time, invalidating our previous work

Idle-time GC

  • Queue.acm.org/detail.cfm?…

API for developers: requestIdleCallback

The browser renders a frame every 16ms

Garbage collection optimization strategy adopted by garbage collector

  • Parallel recovery

The garbage collection optimization strategy adopted by the main garbage collector

  • Parallel collection, concurrent collection, incremental collection
  1.Concurrent reclamation strategy for Mark (all marking work is done in the worker thread)  2.After the marking is completed, a parallel collection strategy is adopted. The main thread and the auxiliary thread clean up simultaneously, and the process is combined with the incremental collection strategy, so that the cleaning task is interspersed between JavaScript tasksCopy the code

thinking

  • How can I avoid memory leaks when using JavaScript?
  1. Objects mounted to global objects need to avoid circular references
  	window.b = new Object(a);window.a = new Object(a);window.b.name = a;
  	window.a.name = b;
  /* b = null; window.a.name = null; The garbage collector marks the b object as garbage data a = NULL; window.b.name = null; The garbage collector marks the a object as garbage data */
Copy the code

  1. When eval is used to create a large or multi-object closure, it is necessary to set the variable of the function to NULL, and the garbage collector will recycle it
  • Recommended article: JavaScript static scope chains versus “dynamic” closure chains

Refer to the article

  • Geek Time: Illustrated GoogleV8
  • MDN- Memory management
  • Understand JavaScript memory management through the garbage collection mechanism
  • .
  • Some of the articles mentioned above will not be repeated