目录
垃圾回收算法
GC算法:
引用计数算法
优点: 及时回收垃圾对象,最大程度的减少程序的暂停。
缺点:无法回收循环引用对象,资源消耗较大(因为要时刻关注引用数的变化)
标记清除算法(标记可达对象,递归查找)
优点:相对于引用计数,解决循环引用不能回收的问题
缺点:相对于垃圾回收会产生空间碎片化问题,空间不能最大化的使用
标记整理算法:标记清除的增强。
标记阶段一致,清除阶段会先执行整理,移动对象的位置
不会出现碎片空间
优点:不会出现碎片空间
缺点:不能立即回收垃圾对象
v8引擎
- 主流js执行引擎
- 及时编译,速度快
- 内存设限 64 1.5G 32 800M
v8垃圾回收策略
采用分代回收的思想:新生代、老生代 不同的算法
- 分代回收
- 空间复制
- 标记清除
- 标记整理
- 标记增量
v8内存分配示意图:
新生代对象(存活时间较短)回收 空间换时间
- 回收过程采用复制算法+标记整理
- 新生代内存区分为两个等大小空间
- 使用空间为Form,空闲空间为TO
- 活动对象存储于Form空间
- 标记整理后将活动对象拷贝至To
- Form与To交换空间完成释放
回收细节说明:
- 拷贝过程中可能出现晋升(当发现对象在一轮GC之后还存活或者To的空间使用率超过25% )
- 晋升就是将新生代对象移动到老生代对象。
老年代对象(存活时间较长的对象)回收:
空间大 不适合复制算法
老生代对象存放在老生代区域 64位1.4G 32 700M
- 主要采用标记清除、标记整理、增量标记的算法
- 首先使用标记清除完成垃圾空间的回收(主要使用)
- 采用标记整理进行空间优化(当新生代内容往老生代移动并且老生代空间不足以存放这些移动的内容)
- 采用增量标记进行效率优化
标记增量优化垃圾回收图:
标记增量就是将一整段的垃圾回收分割成多个小块,然后和程序交替的执行。
新生代老生代细节对比:
- 新生代区域垃圾回收使用空间换时间
- 老生代存储空间大,内容多,不适合使用复制算法
监控内存工具和内存问题的表现
内存问题的外在表现
- 页面出现延迟加载或经常性的暂停(网络环境正常下,出现频繁的垃圾回收,肯定有不合适的代码让存突然暴增)
- 页面持续性出现糟糕的性能(内存膨胀,在不同设备下都出现糟糕的性能)
- 页面的性能随着时间的延长越来越差(内存泄漏)
监控内存的集中方式
界定内存问题的标准:
- 内存泄漏:内存使用持续升高
- 内存膨胀:在多数设备上都存在性能问题
- 频道的垃圾回收:通过内存变化图进行分析
监控内存的工具
- 浏览器任务管理器
JS内存:js堆,小括号里的就是可达对象分配的大小,如果一直增大,说明有问题
- Timeline时序图记录
查看内存走势图,找出问题代码
- 浏览器堆快照查找分离DOM
分离DOM:DOM节点在界面上没有,但是代码里面还存在即内存中还有,造成内存泄漏。
V8引擎工作流程
Scanner: 扫描器 纯文本进行词法分析
Parser: 一个解析器, 语法分析的过程 语法校验
Ignition: V8提供的一个解释器*(预编译和 编译)
TurboFan: v8提供的编译器模块(字节码->汇编代码)
堆栈操作
堆栈准备:
- JS执行环境(v8)
- 执行环境栈(ECStack)
- 执行上下文
- VO(G) 全局变量对象
提高代码效率的一些方法
- 变量局部化
减少全局变量的定义,尽量使用局部变量
- 缓存数据
当需要多次访问一个对象的属性时,可以使用一个变量将该属性值缓存起来,之后就不需要再从对象上去查找了。
- 减少访问层级
扁平化 等
- 减少判断层级
函数中使用return去结束函数的执行,避免多次if if else的代码
- 减少使用new创建字符串 对象等
避免使用 new Object() new String()这些去创建对象,字符串,数组等
- 减少循环体的活动
循环体内只写必要的代码,一些共同的代码应该提出去