从以下三个方面了解垃圾回收:
内存泄漏
本质上,内存泄露可以定义为:应用程序不再需要占用内存的时候,由于某些原因,内存没有被操作系统或可用内存池回收。
对于持续运行的服务进程,必须及时释放内存,否则,内存占用越来越高,轻则影响系统性能,重则导致进程崩溃。
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。
- 如果保存对该值引用的变量被其他值给覆盖了,那么引用数减1。
- 当一个值的引用数为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。
总结
- 内存没有释放或释放及时会造成内存泄漏。
- 垃圾回收机制的常用方式是标记清除和引用计数。
- 查看内存泄漏可以通过浏览器和命令行的方式。
- 常见的容易造成内存泄漏有:未定义的全局变量,未及时释放的订阅事件和定时器