内存管理
- 内存:由可读但愿组成,表示一片可操作空间
- 管理:人为的去操作一片空间的申请、使用和释放
- 内存管理:开发者主动申请空间、使用空间、释放空间
- 管理流程: 申请-使用-释放
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();
优点:
- 发现垃圾时立即回收
- 最大限度减少程序暂停(当内存到达峰值时会立即进行垃圾回收)
缺点:
- 无法回收循环引用的对象
- 时间开销大(需要时刻监控引用数值的变化)
标记清除
分标记和清除两个阶段完成
遍历所有对象(层级嵌套时使用递归)找到标记活动对象、遍历所有对象清除标记对象(不再具有引用关系时抹除标记)
回收相应的空间(回收后的内存会添加到空闲链表上方便申请使用)
优点: 相对于引用计数解决了循环引用不能回收的问题
缺点: 会产生空间碎片化问题(内存回收过程中的不连续问题),使得内存空间不能最大化的使用
标记整理算法
标记清除的增强版本
标记阶段的操作和标记清除一致
清除阶段会限制性整理,移动对象位置
优点: 解决了标记清除的空间不连续问题
v8
主流的Javascript执行引擎
采用即时编译
内存设限 64位操作系统(1.5G) 32位操作系统(800M)
垃圾回收策略
- 采用分代回收机制
- 内存分为新生代、老生代
中常用的gc算法
- 分代回收
- 空间复制
- 标记清除
- 标记整理
- 标记增量
内存分配
- V8内存空间一分为二
- 小空间用于存储新生代对象(32M|16M)
- 新生代是指存活时间较短的对象
新生代回收实现
- 回收过程采用复制算法 + 标记整理
- 新生代内存分为二个等大小空间
- 使用空间为From,空闲空间为To
- 活动对象存储于From空间
- 标记整理后将活动对象拷贝至To
- From与To交换空间完成释放
回收细节说明
- 拷贝过程中可能出现晋升
- 晋升就是将新生代对象移动至老生代
- 一轮GC还存活的新生代需要晋升
- To空间的使用率超过25%
老生代对象
老生代对象存放在右侧老生代区域(1.4G|700M)
老生代对象回收实现
- 主要采用标记清除、标记整理、增量标记算法
- 首先使用标记清除完成垃圾空间的回收
- 采用标记整理进行空间优化(新老对象互换)
- 采用增量标记进行效率优化
细节对比
- 新生代区域垃圾回收使用空间换时间
- 老生代区域垃圾回收不适合复制算法