Node进阶 - 内存管理和垃圾回收
Node内存管理和垃圾回收
node.js 是基于 V8 引擎的 javascript 运行环境。
V8 引擎
javascript 代码运行的时候提供编译优化、内存管理、垃圾回收等功能
代码编译优化:
1、通过 parser 将 javascript 源码转为 ast 抽象语法树
2、将 ast 抽象语法树转为字节码,
3、然后转为机器可运行的汇编代码
内存管理:管理内存分配、内存划分
垃圾回收:通过垃圾回收机制对无用代码释放内存
内存管理
类型
常驻内存:运行 node 进程时候的所有内存( 代码占用内存、栈内存、堆内存、堆外内存 )
栈内存:用于存放变量( javascript 中基本类型 )
堆内存:用于存放对象、闭包引用上下文( 引用类型 )
堆外内存:不是通过 V8 分配,不受V8管理,不占用V8内存。一些用于存放 buffer 数据的 ( buffer 对象依然在堆内存中 )
限制
默认给堆内存分配的大小:64位系统为 1.4G、32位系统为 0.7G
可以通过 node 启动命令修改内存大小。
不过分配的内存越大,垃圾回收一次的时间越长
内存信息获取
node 提供了 process.memoryUsage() 获取当前进程的内存信息
rss :常驻内存大小( 进程分配的内存 )
heapTotal:给 V8 分配的内存大小
heapUsed:已使用的堆内存大小
external:堆外使用的内存( buffer )
1、内存溢出和堆外内存
const fs = require('fs') const format = function (item, type = 0) { let ext = 'byte' switch (type) { case 1: ext = 'KB' break; case 2: ext = 'M' break; case 3: ext = 'G' break; case 3: ext = 'T' break; } if (item < 1024) return item.toFixed(2) + ext return format(item / 1024, type + 1) } function showMemory() { const memoryUsage = process.memoryUsage() console.log(`---------------------`) for (const item in memoryUsage) { console.log(`${item}:${format(memoryUsage[item])}`) } } showMemory() // 使用 40M 堆外内存 const buffer = new ArrayBuffer(40 * 1024 * 1024) const total = [] setInterval(() => { // 20M 内存的添加 total.push(new Array(20 * 1024 * 1024)) showMemory() },2000)
垃圾回收
释放一些在应用程序中不在被引用,或者空指针的一些变量的内存。
1、变量为空的时候释放内存栈
2、对象结束没引用或者引用的对象被清除的时候释放对应内存( 对象无法被根节点访问时候 )
堆内存中的分类
新生代:内存比较小,未经历垃圾回收的对象存放位置
from 区:回收检查( 算法回收 ) 的时候,检查区
to 区:回收检查( 算法回收 ) 的时候,from检查到对象被引用存活了
老生代:内存是新生代20倍,from 区收检查( 算法回收 ) 的时候,已经经历过的对象或者to区满了时候送到老生代
新生代垃圾回收
新生代垃圾回收是通过交换 from 区和 to 区来实现的
1、新建的对象被存放在 from 区,满了之后执行新生代垃圾回收检查
2、检查 from 区对象,如果已经经历过一次检查且依然被引用的对象送到老生代区
3、检查 from 区对象,如果被引用则总到 to 区,to 区满了25%则送到老生代区
4、结束 from 检查后,交换 from 区和 to 区身份( from 区变 to区,反之 )
5、再次检查,回到 1。
老生代垃圾回收
老生代垃圾回收没有新生代频繁
主要通过判断是否被引用进行标记清除,然后对存活的对象整理
1、检查老生代区,是否被引用,未被引用,释放该内存块的内存
2、将依旧存活的对象,整理到老生代区的一端
3、清除存活一端以外部分的内存块
堆内存里面的对象主要是靠引用计数来判断是否释放内存(每引用一次增加1)
内存泄漏场景
1、未释放无用的全局变量/对象
2、闭包的上下文
function add() { const x = 1; const y = 2; return function (a) { return y + 2 } } const add1 = add(); /* * 执行 add() 后 * x 将会被释放 * y 将存在 add1 的上下文中,不会被释放( 除非 add1 = null ) * */
3、缓存大量数据
// 分成小的一部分一部分处理 const array = new Array(20 * 1024 * 1024)
内存分析工具
利用内存检查工具( node-heapdump、node-profiler ) 生成内存快照
利用 chrome 进行分析。