第一章 概念
内存: 可读写单元组成
内存管理: 开发者 => 申请 使用 释放
模拟
申请: 变量定义是自动分配 let obj = {}
使用: obj.name ="guohai"
释放: obj = null
垃圾: JavaScript 内存管理是自动的, 对象不再被引用, 非可达
可达对象:从根 EC(G)> VO(G)出发可以访问到的对象 // 引用 作用域链
GC算法 : 垃圾回收机制, 找垃圾,释放/回收空间
引用计数:
原理: 设置对象引用数,引用关系改变时改变. 判断是否为0 (0)=> 垃圾 => ♻️
优: 发现垃圾立刻回收, max减少程序pause
缺: 无法回收循环引用对象,资源开销大
标记清除:
原理:分2阶段(遍历标记all可达对象,遍历清除清没有标记的对象+除标记)=> ♻️
优:可以回收循环引用对象
缺:空间碎片化🧩 不能立刻回收,回收时程序pause
标记整理:
原理:分3阶段(遍历标记all可达对象 -- 整理 -- 遍历清除清没有标记的对象+除标记)=> ♻️
V8: 主流JavaScript执行引擎 , 即时编译,内存设限( 1.5G64位 / 800MB32位 )
处理的数据是:对象数据(回收主要关注这个,堆内存内的♻️)= 分代回收策略(新 / 老)
原始数据 由 程序语言自身控制
V8回收策略:新 / 老 =(分代, 空间复制, 标记清楚, 标记整理,标记增量)
新生代回收(32MB/16MB): 存活较短,eg:局部作用域
方法: 空间复制 标记整理
名词: from 使用空间, to 空闲空间
步骤:1. 若需空间首先分配到from空间,2.当from空间使用到达触发比例, 3.对from进行标记整理,4之后将可达对象复制到to空间,5.释放from,6.调换 from 和 to
晋升:1.一轮g后还在 2. to空间超过25%
老生代回收(1.4G/700MB)eg: 全局,闭包
方法: 标记清除 标记整理 增量标记
步骤:1. 标记清楚释放不可达对象 2. 当自身空间不够,进行标记整理(增量标记:垃圾回收分段)
第二章 工具
内存问题体现:
1. 延迟加载,经常性暂停(频繁垃圾回收)
2. 持续糟糕(内存膨胀) -- 程序运行需要的内存太大,设备匹配(要的太多还是你根本给不了)
3. 越来越差(内存泄漏) -- 内存持续升高
监控方式:
1. 任务管理器(memeory footprint 原生内存 = DOM related, Javascript memory 堆, 括号里可达对象)
2. timeline
3. 堆快照 找分离DOM(一定程度时内存浪费)detached
判断是否有频繁垃圾回收:
表现: 卡顿
检测: timleine中频繁上下窜升,任务管理器中数据频繁增加减少
V8 工作流程
渲染引擎 => 包含v8
词法分析, 语法分析
预解析(声明不调用,声明不赋值)/全量解析(立即调用)
解释器 ignition
编译器模块 TurboFan (字节码 变成 机器码)
堆与栈(🔗直播笔记)
基本数据类型按值访问,其值放在栈区。引用类型在堆区,按照地址访问
闭包 与 回收
堆内存:被引用 =>无法释放, 可手动断开链接来释放
栈内存:当前执行上下文中 内容 被 其他上下文中的 引用 => 无法释放
性能优化实例
1. 实例: 循环事件添加 对比(问题代码 => 闭包 =>局部变量let => DOM自定义属性)
2. JSBench 测试工具 测试代码效率
3. 局部变量 减少数据访问路径 => 快
4. 函数参数缓存 => 以便多次使用 => 快
5. 减少数据访问层级 (eg: object structure)
6. 减少判断层级(提前return 无用条件) => 优
7. 减少循环体活动(例如 arr.length 提起存储, 常用不变的数据 提取出来) => 优
8. while 循环 if possible
let len = 3
while (len--) {console.log(len)}
9. 字面量 > new构造 =====> 效率高