Javascript中的内存管理

/post/memory-manage article cover image

内存管理

  • 内存:由可读但愿组成,表示一片可操作空间
  • 管理:人为的去操作一片空间的申请、使用和释放
  • 内存管理:开发者主动申请空间、使用空间、释放空间
  • 管理流程: 申请-使用-释放

Javascript中内存管理

js
// 申请
var obj = { };

// 使用
obj.a = 1;

// 释放
obj = null;

javascript中的垃圾回收

  • Javascript中内存管理是自动的
  • 对象不再被引用时
  • 对象不能从根上访问到时

gc算法

Garbage Collection: 根据引用规则自动找到内存中的垃圾、并释放和回收空间的机制

<u>常见的GC算法:</u>

  • 引用计数
  • 标记清除
  • 标记整理
  • 分代回收

引用计数算法

使用引用计数器设置引用数量,判断当前引用数据是否为0

引用关系改变时修改引用数量,引用数字为0时立即回收

js
const a = 1;

const list = [a];

function fn() {
	const innerVal = 'xxx';
}

// 因为a被list引用,所以即使fn执行结束以后a也不会被回收
fn();

优点:

  1. 发现垃圾时立即回收
  2. 最大限度减少程序暂停(当内存到达峰值时会立即进行垃圾回收)

缺点:

  1. 无法回收循环引用的对象
  2. 时间开销大(需要时刻监控引用数值的变化)

标记清除

分标记和清除两个阶段完成

遍历所有对象(层级嵌套时使用递归)找到标记活动对象、遍历所有对象清除标记对象(不再具有引用关系时抹除标记)

回收相应的空间(回收后的内存会添加到空闲链表上方便申请使用)

优点: 相对于引用计数解决了循环引用不能回收的问题

缺点: 会产生空间碎片化问题(内存回收过程中的不连续问题),使得内存空间不能最大化的使用

标记整理算法

标记清除的增强版本

标记阶段的操作和标记清除一致

清除阶段会限制性整理,移动对象位置

优点: 解决了标记清除的空间不连续问题

v8

主流的Javascript执行引擎

采用即时编译

内存设限 64位操作系统(1.5G) 32位操作系统(800M)

垃圾回收策略

  • 采用分代回收机制
  • 内存分为新生代、老生代

中常用的gc算法

  • 分代回收
  • 空间复制
  • 标记清除
  • 标记整理
  • 标记增量

内存分配

  • V8内存空间一分为二
  • 小空间用于存储新生代对象(32M|16M)
  • 新生代是指存活时间较短的对象

新生代回收实现

  • 回收过程采用复制算法 + 标记整理
  • 新生代内存分为二个等大小空间
  • 使用空间为From,空闲空间为To
  • 活动对象存储于From空间
  • 标记整理后将活动对象拷贝至To
  • From与To交换空间完成释放

回收细节说明

  • 拷贝过程中可能出现晋升
  • 晋升就是将新生代对象移动至老生代
  • 一轮GC还存活的新生代需要晋升
  • To空间的使用率超过25%

老生代对象

老生代对象存放在右侧老生代区域(1.4G|700M)

老生代对象回收实现

  • 主要采用标记清除、标记整理、增量标记算法
  • 首先使用标记清除完成垃圾空间的回收
  • 采用标记整理进行空间优化(新老对象互换)
  • 采用增量标记进行效率优化

细节对比

  • 新生代区域垃圾回收使用空间换时间
  • 老生代区域垃圾回收不适合复制算法