可达对象
- 可以访问到的对象就是可达对象(引用、作用域链)
- 可达的标准就是从根*(全局对象,即全局执行上下文)*出发是否能够被找到
function objGroup(obj1, obj2) {
obj1.next = obj2
obj2.prev = obj1
return {
o1: obj1,
o2: obj2
}
}
let obj = objGroup({name: 'obj1'}, {name: 'obj2'})
console.log(obj)
上面这段代码里的每个对象都可以通过路径访问到,那么所有的元素都是可达对象,如果路径被破坏了,不可达对象就会变成垃圾
GC算法
**GC里的垃圾定义:**程序中不再需要使用的对象和程序中不能再访问到的对象
GC算法是什么
GC是一种机制,垃圾回收器完成具体的工作
工作的内容就是查找垃圾释放空间、回收空间
算法就是工作时查找和回收所遵循的规则
引用计数算法
**核心思想:**设置引用数,判断当前引用数是否为0,是的话GC算法就开始工作,清除当前的垃圾占用的空间
优点
- 发现垃圾时立即回收
- 最大程度减少程序暂停
缺点 - 无法回收循环引用的对象
- 时间开销大,资源消耗大
标记清除算法
**核心思想:**分为标记和清除两个阶段完成,标记阶段遍历所有对象找标记活动对象,清除阶段遍历所有对象清除没有标记的对象,最后GC开始工作回收相应的空间
优点
- 可以解决循环引用无法回收的问题
缺点 - 会导致空间碎片化,即地址不连续,浪费空间
- 不会立即回收垃圾对象
标记整理算法
**核心思想:**分为标记和清除两个阶段完成,标记阶段遍历所有对象找标记活动对象,清除阶段会先执行整理,移动对象位置
优点
- 可以减少碎片化空间
缺点 - 不会立即回收垃圾对象
V8
V8是一款主流的JavaScript执行引擎,采用即时编译,
64位系统的最大内存为1.5G,32位为800M
V8垃圾回收策略
- 采用分代回收的思想
- 内存分为新生代、老生代
- 针对不同对象采用不同算法
V8内存分配 - V8内存空间一分为二
- 小空间用于存储新生代对象(32M | 16M)
- 新生代指的是存活时间较短的对象,比如局部作用域里的变量,方法调用完毕就回收
新生代对象回收实现
- 回收过程采用复制算法+标记整理
- 新生代内存区分为两个等大小空间
- 使用空间为From,空闲空间为To
- 活动对象存储于From空间
- 标记整理后将活动对象拷贝至To
- From与To交换空间完成释放
老生代对象回收实现
- 主要采用标记清除(清除老生代空间)、标记整理(为新生代晋升提供空间)、增量标记算法(将整块垃圾拆分成各个小段减少程序暂停时间)
- 首先使用标记清除完成垃圾空间的回收
- 采用标记整理进行空间优化
- 采用增量标记进行效率优化
老生代和新生代对比
- 新生代区域垃圾回收使用空间换时间
- 老生代区域垃圾回收不适合复制算法
内存监控
shift+esc打开浏览器任务管理器,其中的内存指dom占据的内存(频繁操作dom时会增加),js内存表示js的堆,括号中表示js的可达对象正在使用的内存(创建新对象和已有对象变大时会增加)
界定内存问题的标准
- **内存泄漏:**内存使用持续升高
- **内存膨胀:**在多数设备上都存在性能问题
- **频繁垃圾回收:**通过内存变化图进行分析,timeline频繁的上升下降,任务管理器中数据频繁的增加减小
- GC工作时应用程序是停止的
- 频繁且过长的GC会导致应用假死
- 用户使用中感知应用卡顿
其它优化方法
- 减少使用全局变量
- 在局部作用域中缓存全局变量
- 通过原型对象添加附加方法
- 减少使用闭包,在使用完闭包后及时手动清除
- 对象属性直接使用的效率比添加方法访问高
- for循环中将length存到变量中减少每次计算时间