jsMemory management mechanism

  • jsMemory is allocated automatically when variables (objects, strings, and so on) are created, and inDo not useWhen theyautomaticRelease. The process of release is calledThe garbage collection.
  • automaticIs a source of confusion, and letjsDevelopers mistakenly feel they can afford not to care about memory management.
  • jsThere is a one-to-one correspondence between the memory management mechanism and the memory life cycleAllocate memoryAnd thenThe use of memoryAnd the lastFree memory.
  • jsLanguages do not require programmers to manually allocate memory, and in most cases do not require programmers to manually free memory, rightjsProgrammers usually doThe use of memory(that is, using variables, functions, objects, etc.)

Memory allocation

// Allocate memory for Boolean variables
let flag = true;
// Allocate memory for string variables
let str = 'hello';
// Allocate memory for arrays and their values
let arr = [2.null.'aa'];
// Allocate memory to the function
function fn (a) {
  return a;
}
Copy the code

Memory usage

  • The process of working with values is actually reading and writing to allocated memory.
  • Reading and writing may be writing the value of a variable or an object property, or even passing the parameters of a function.
// Write to memory
str = 'byebye';
// read STR and fn's memory, write fn's parameter memory
fn(str);
Copy the code

Memory recovery

  • Garbage memory collectionGC(Garbage Collection)
  • This is where memory leaks usually occur,jsAlthough the memory reclamation mechanism can recycle most of the garbage memory, but there are still cases that can not be reclaimed, if this situation exists, you need to manually clean the memory.

jsThere are two ways to recycle garbage

Reference counting garbage collection

  • Simplify the definition of “is an object no longer needed” to “does an object have other objects that refer to it?”
  • If there are no references to the object (zero references), the object will be collected by the garbage collection mechanism.
// Assign the object literal to the a variable
let a = {
  a: 1.b: 2
}
// b references a variable
let b = a;
// a is assigned to 1, replacing the reference to the object literal with b
a = 1;
Copy the code
  • In the current execution environment, the memory of object literals has not been reclaimed and needs to be freed manually.
// or b = 1, replace the "object literal" so that it is no longer referenced
b = null;
Copy the code

Mark clearance

  • Variables are marked as “in” when they enter the execution environment and “out” when they leave the execution environment. Variables marked as “in” cannot be reclaimed because they are in use, whereas variables marked as “out” can be reclaimed.
  • Context can be thought of as scope, but globally-scoped variables are destroyed only when the page is closed.
// Suppose this is: global scope
// b is marked: enter the environment
var b = 100;
function add () {
  var a = 1;
  // when the function executes, a is marked to enter the environment
  return a + b;
}
add();
// When the function completes, a is marked out of the environment and recycled
// But b is not marked out of the environment, because b is a global variable and will be destroyed only after the page is closed.
Copy the code

jsMemory Leak Scenario

  • The following example: is in the execution environment, does not leave the current execution environment, but also triggers the tag purge.

Unexpected global variables

// Defined in global scope
function count(number) {
  // basicCount = window.basicCount = 2;
  basicCount = 2;
  return basicCount + number;
}
Copy the code
  • It is now possible to avoid such mistakes,eslintAn error is reported directly.

The forgotten timer

  • Delete useless timers.
<template>
  <div></div>
</template>

<script>
export default {
  methods: {
    refresh() {
      // Get some data}},mounted() {
    setInterval(function() {
      // Polling to get data
      this.refresh()
    }, 2000)}},</script>
Copy the code
  • When the above components were destroyed,setIntervalIt is still running, the memory involved is not retrievable (the browser will consider it required memory, not garbage memory), and the timer needs to be cleared when the component is destroyed, as follows:
<template>
  <div></div>
</template>

<script>
export default {
  methods: {
    refresh() {
      // Get some data}},mounted() {
    this.refreshInterval = setInterval(function() {
      // Polling to get data
      this.refresh()
    }, 2000)},// Clear timer before component destruction
  beforeDestroy() {
    clearInterval(this.refreshInterval)
  },
}
</script>
Copy the code

Forgotten event listeners

  • Clean up useless event listeners.
<template>
  <div></div>
</template>

<script>
export default {
  mounted() {
    window.addEventListener('resize'.() = > {
      // Do some operations here}})},</script>
Copy the code
  • When the above components were destroyed,resizeThe event is still in the listener, and the memory involved in it is not retrievable (the browser will consider it required memory, not garbage memory). The related events need to be removed when the component is destroyed, as follows:
<template>
  <div></div>
</template>

<script>
export default {
  mounted() {
    this.resizeEventCallback = () = > {
      // Do some operations here
    }
    window.addEventListener('resize'.this.resizeEventCallback)
  },
  // Remove listening events before component destruction
  beforeDestroy() {
    window.removeEventListener('resize'.this.resizeEventCallback)
  },
}
</script>
Copy the code

The forgottenMembers of the ES6 Set \ Map

  • setandmapThe error is handled the same way
let map = new Set(a);let value = { test: 22};
map.add(value);

// Only zero references are made to value, but the set is still present
value= null;
Copy the code
  • Need to change as follows:
let map = new Set(a);let value = { test: 22};
map.add(value);

map.delete(value);
value = null;
Copy the code

Forgotten subscribe publish event listener

  • Correct term
<template>
  <div @click="onClick"></div>
</template>

<script>
import customEvent from 'event'

export default {
  methods: {
    onClick() {
      customEvent.emit('test', { type: 'click'})}},mounted() {
    customEvent.on('test'.data= > {
      // Some logic
      console.log(data)
    })
  },
  // Remove the timer and event listener before the component is destroyed
  beforeDestroy() {
    customEvent.off('test')}},</script>
Copy the code

Forgotten closures

  • There is a memory leak as follows:
function closure() {
  const name = 'xianshannan'
  return () = > {
    return name
      .split(' ')
      .reverse()
      .join(' ')}}// Execution not called, memory leak
const reverseName = closure()
Copy the code
  • In the case of the current execution environment, which is technically a memory leak,nameVariables areclosureThe returned function is called, but the returned function is not usednameIt’s junk memory.nameNot required, but still takes up memory and cannot be reclaimed.

Out of theDOMA reference to the

  • On every pageDOMThey’re all memory hogging, so let’s say I have a pageAElement, we got itAThe elementDOMObject, then assign to a variable (memory pointing is the same), then remove the pageAElement, if the variable is not collected for some other reason, then there is a memory leak as follows:
class Test {
  constructor() {
    this.elements = {
      button: document.querySelector('#button'),
      div: document.querySelector('#div'),
      span: document.querySelector('#span'),}}removeButton() {
    document.body.removeChild(this.elements.button)
    // this.elements.button = null}}const a = new Test()
a.removeButton()
Copy the code
  • The example abovebuttonThe element is removed from the page, but the memory point is changed tothis.elements.buttonThe memory footprint is still there. So the above code also needs to be written like this:this.elements.button = nullManually release the memory.

The appendix

  • See the article for more on JavaScript memory leaks