垃圾回收
- js中内存管理是自动的
- 对象不再被引用时是垃圾
对象不能从根上访问到时是垃圾可达对象:1.可以访问到的对象就是可达对象 2.可达标准是从根出发是否能被找到 3.js中的根可以理解为全局变量对象
GC算法
引用计数算法
- 核心思想:设置引用数,判断当前引用数是否为0
- 引用计数器
- 引用关系改变时修改引用数字
- 引用数字为0时立即回收
- 引用计数算法优缺点
- 发现垃圾时立即回收
- 最大限度减少程序暂停
- 无法回收循环引用的对象
- 时间开销大
- 标记清除算法
- 核心思想:分标记和清除两个阶段完成
- 遍历所有对象找标记活动对象(递归查找)
- 遍历所有对象清除没有标记的对象,同时把第一次遍历所做的标记抹掉
- 把回收的空间放到空闲列表上面,方便后续程序申请空间使用
- 标记清除算法优缺点
- 可以解决循环引用的对象
- 地址不连续,空间碎片化
- 标记整理算法
- 是标记清除的增强
- 标记阶段的操作和标记清除一致
- 清除阶段会先执行整理,移动对象位置
- V8引擎
- 即时编译
- V8内存设限 64位 1.5G 32位 800M
- V8垃圾回收策略
- 采用分代回收的思想
- 内存分为新生代、老生代
- 针对不同对象采用不同算法
1. 分代回收1. 空间复制1. 标记清除1. 标记整理1. 标记增量
- V8内存分配
- V8内存空间一分为二
- 小空间用于存储新生代对象(64位:32M | 32位:16M)
- 新生代指的是存活时间较短的对象(局部作用域中的变量)
- 新生代对象回收实现
- 回收过程采用复制算法 + 整理标记
- 新生代内存区分为两个等大小空间
- 使用空间为From,空闲空间为To
- 所有对象存储于From空间(包括活动对象和非活动对象)
- 当From空间应用到一定程度后会触发GC机制,标记整理后将活动对象拷贝至To
- From完成释放(From和To交换空间)回收细节说明:
- 拷贝过程中可能出现晋升
- 晋升就是讲新生代对象移动至老生代
- 一轮GC还存活的新生代需要晋升
- To空间的使用率超过25%需要晋升至老生代
- 老生代对象回收
- 老生代对象存放在右侧老生代区域
- 64位限制1.4G,32位限制700M
- 老生代对象就是指存活时间较长的对象(全局变量,闭包)
实现过程:- 主要采用标记清除、标记整理、增量标记算法
- 首先使用标记清除完成垃圾空间的回收
- 采用标记整理进行空间优化(当新生代晋升老生代时,同时也发现老生代空间不够存新生代晋升过来的,就会进行标记整理空间优化)
- 采用增量标记进行效率优化(将标记过程分段进行)
- 内存问题的外在表现
- 页面出现延迟加载或经常性暂停
- 页面持续性出现糟糕的性能(内存膨胀,分配的内存超过机器能力)
- 页面的性能随时间延长越来越差(内存泄漏)
- 监控内存的几种方法
界定内存问题的标准
- 内存泄漏:内存使用持续升高
- 内存膨胀:在多数设备上都存在性能问题
- 频繁垃圾回收:通过内存变化图进行分析监控方式:
- 浏览器任务管理器
- TImeline时序图记录
- 堆块照查找分离DOM(分离DOM存在是一种内存泄漏)
- 判断是否存在频繁的垃圾回收
- 什么是分离DOM
- 慎用全局变量
- 所有作用域链的顶端,所以会比较耗时,尽量放在局部作用域
- 不利于GC机制,耗内存
- 全局变量命名污染
- 缓存全局变量
- 通过原型新增方法来替代构造函数中新增方法
- 避开闭包陷阱(容易内存泄漏)
- 避免属性访问方法使用
- for循环优化。将长度缓存
- 采用最优循环方式:简单遍历的话 foreach 优于 for 优于 for in
- 节点添加优化(回流和重绘):createDocumentFragment() 文档碎片方法优于直接添加到body
- 克隆优化节点操作:cloneNode(false)
- 直接量替换Object操作```
var a = [1, 2, 3] // 性能好
var a1 = new Array(3)
a1[0] = 1
a1[1] = 2
a1[2] = 3
