从以下三个方面了解垃圾回收:

内存泄漏

本质上,内存泄露可以定义为:应用程序不再需要占用内存的时候,由于某些原因,内存没有被操作系统或可用内存池回收。

对于持续运行的服务进程,必须及时释放内存,否则,内存占用越来越高,轻则影响系统性能,重则导致进程崩溃。

JS中常见的内存泄漏

意外的全局变量

未定义的变量会在全局对象创建一个新变量。在浏览器中,全局对象是 window 。

列如:

function foo(arg) { 
    bar = "this is a hidden global variable"; 
} 

实际上:

function foo(arg) { 
    window.bar = "this is an explicit global variable"; 
}

函数 foo 内部忘记使用 var ,意外创建了一个全局变量。此例泄露了一个简单的字符串。

由 this 创建的全局变量

function foo() { 
    this.variable = "potential accidental global"; 
} 
 
// Foo 调用自己,this 指向了全局对象(window) 
// 而不是 undefined 
foo(); 

在 JavaScript 文件头部加上 'use strict',可以避免此类错误发生。启用严格模式解析 JavaScript ,避免意外的全局变量。

被遗忘的计时器或回调函数

在 JavaScript 中使用 setInterval 非常平常。

var someData = getData(); 
setInterval(function() { 
    console.log(someData)
}, 1000);

由于计时器没有停止,那么它其中的变量 someData 也无法被回收,如果someData存储了大量的数据,将照成严重的内存浪费。

我们在使用一些监听事件的时候也要格外小心,例如,监听窗口变化的onResize函数:

// 事件订阅
window.onresize=function(){SomeJavaScriptCode};

// 取消订阅
window.onresize = null;

不取消对事件的订阅不一定会导致内存泄漏。例如,当创建具有<button>事件订阅的click时,一旦<button>从DOM中删除并且该代码中没有引用,该订阅将被删除。

垃圾回收策略

  • 标记清楚
  • 引用计数

标记清除

垃圾回收程序执行的时候都做了什么?

1.标记内存中存储的所有变量

2.将所有在上下文中的变量,以及被在上下文中的变量引用的变量的标记去掉

3.垃圾回收程序做一次内存清理,销毁带标记的所有值并收回它们的内存

引用计数

思路是对每个值都记录它被引用的次数。

  1. 声明变量并给它赋一个引用值时,这个值的引用数为1。
  2. 如果同一个值又被赋给另一个变量,那么引用数加1。
  3. 如果保存对该值引用的变量被其他值给覆盖了,那么引用数减1。
  4. 当一个值的引用数为0 时,就说明没办法再访问到这个值了,因此可以安全地收回其内存了。垃圾回收程序下次运行的时候就会释放引用数为0 的值的内存。

存在的问题:

循环引用

查看内存使用情况

process.memoryUsage()方法是进程模块的内置方法,提供有关Node.js程序的当前进程或运行时的信息。它返回一个对象,该对象描述 Node.js 进程的内存使用情况(以字节为单位)。

示例:

// Requiring module
var process = require('process')

// An example displaying the respective memory
// usages in megabytes(MB)
for (const [key, value] of Object.entries(process.memoryUsage())) {
  console.log(`Memory usage by ${key}, ${value / 1000000}MB `)
}

// Memory usage by rss, 23.191552MB
// Memory usage by heapTotal, 5.791744MB
// Memory usage by heapUsed, 3.015496MB
// Memory usage by external, 1.11954MB
// Memory usage by arrayBuffers, 0.01809MB
  • heapTotal and heapUsed V8引擎内存的使用情况
  • external V8 引擎管理的绑定到JS对象上的C++对象的内存使用情况
  • rss:Resident Set Size, 驻留集大小,是为进程占用的主内存设备(即总分配内存的子集)中的空间量,包括所有 C + + 和 JavaScript 对象和代码。
  • arrayBuffers 指为 ArrayBuffers 和 SharedArrayBuffers 分配的内存,包括所有 Node.js Buffers。

总结

  1. 内存没有释放或释放及时会造成内存泄漏。
  2. 垃圾回收机制的常用方式是标记清除和引用计数。
  3. 查看内存泄漏可以通过浏览器和命令行的方式。
  4. 常见的容易造成内存泄漏有:未定义的全局变量,未及时释放的订阅事件和定时器