申请内存空间
使用内存空间
释放内存空间
引用计数
标记清除
标记整理
分代回收
核心思想:设置引用数,判断当前引用数是否为0
引用计数器
引用关系改变时,修改引用数字
引用数字为0时立即回收
根据当前引用数是否为0,来决定这个对象是不是垃圾,如果判定为垃圾,立即进行释放
应用程序在执行过程中,必然会对内存进行消耗,而内存空间是有上限的,当内存快被占满时,引用计数会找到引用数为0的对象,进行释放
上图代码中,当代码执行完后,虽然在全局中,已经找不到obj1和obj2,但是在函数内,由于相互引用,所以obj1和obj2的引用计数就不是为0,造成引用计数算法无法回收这2个对象的内存空间,造成了内存空间浪费。
因为当前的引用计数需要去维护一个数值的变化,所以在这种情况下,要时刻监控当前对象的引用数值是否需要修改,对象引用计数的修改就需要消耗时间,需要修改的对象越多,则需要的时间也就越多。
核心思想:分标记和清除二个阶段完成
遍历所有对象找标记活动对象
遍历所有对象清除没有标记对象
回收相应的空间
通过2次的遍历行为,把当前的垃圾空间进行回收,最终交给空闲列表进行维护。
解决了引用计数无法回收循环引用对象的问题
会造成空间碎片化。
由于所回收的对象在内存地址上是不连续的,因此造成空闲区间也是不连续的。
标记整理算法可以看做是标记清除算法的增强
标记阶段的操作和标记清除算法一致
清除阶段会先执行整理,移动对象位置,让地址产生连续
会先把活动对象进行标记,然后进行整理,将活动对象进行移动,在地址上变成连续的位置,
然后将活动对象整理后以外的区域进行整体回收,
这样就使得回收后的空间是连续的
2
V8是一款主流的 JavaScript 执行引擎, Chrome浏览器、NodeJs都在使用
V8采用即时编译,将源码翻译成当前可以直接执行的机器码,使得执行速度很快
V8内存设限,64位操作系统不超过1.5G, 32位操作系统不超过800M
采用分代回收的思想
内存分为新生代、老生代
针对不同对象采用不同算法
分代回收
空间复制
标记清除
标记整理
标记增量
V8内存分配
V8内存空间一分为二,左侧用于存储新生代对象
小空间用于存储新生代对象 (64位操作系统大小是 32M | 32位操作系统大小是 16M)
新生代指的是存活时间较短的对象,如函数内声明的对象
回收过程采用空间复制算法 + 标记整理
新生代内存区分为二个等大小空间
使用空间为 From, 空闲空间为 To
活动对象存储于 From 空间
标记整理后将活动对象拷贝至 To
From 与 To 交换空间完成释放
拷贝过程中可能出现晋升,拷贝过程中如果某个变量所指引的空间在当前的老生代对象里也会出现,这时候就会出现晋升操作
晋升就是指将新生代对象移动至老生代进行存储
一轮 GC后 还存活的新生代需要晋升
To 空间的使用率超过 25%时,将活动对象移动至老生代进行存储
老生代对象存放在右侧老生代区域
内存大小限制:64位操作系统 1.4G , 32位操作系统 700M
老生代对象就是指存活时间较长的对象:如果全局对象,闭包内的对象
主要采用标记清除、标记整理、增量标记算法
首先使用标记清除完成垃圾空间的回收
采用标记整理进行空间优化:当有新生代对象往老生代存储区域进行移动的时候,而这时老生代存储空间不足以存放新生代对象时,这时候就会触发标记整理
采用增量标记进行效率优化
当垃圾回收进行工作时,会阻塞 JavaScript 程序执行。
将我们一整段的垃圾回收操作,拆分成多个小步,组合着去完成当前整个垃圾回收。
实现垃圾回收和程序执行交替完成,这样所带来的时间消耗会更加合理一些。
新生代区域垃圾回收使用空间换时间
老生代由于存储空间大,因此老生代区域垃圾回收不适合不适合复制算法
打开浏览器输入目标网址
进入开发人员工具面板,选择性能
开启录制功能,访问具体界面
执行用户行为,一段时间后停止录制
分析界面中记录的内存信息
页面出现延迟加载或经常性暂停:与GC存在着频繁地垃圾回收操作相关,之所以会存在频繁垃圾回收操作,说明是有一些代码瞬间让内存爆掉了,需要去进行定位。
页面持续性出现糟糕性能表现:说明存在着内存膨胀,当前界面为了达到最佳的使用速度,去申请了一定的内存空间,而这所需要的的内存空间大小远超过了当前设备所能提供的内存大小
页面的性能随时间延长越来越差: 说明存在着内存泄漏
浏览器任务管理器
Timeline 时序图记录
堆快照查找分离 DOM
判断是否存在频繁的垃圾回收
GC 工作时应用程序是停止的
频繁且过长的 GC 会导致应用假死
用户使用中感知应用卡顿
Timeline 中频繁的上升下降
任务管理器中数据频繁的增加减小
慎用全局变量
缓存全局变量
缓存全局变量
1111
222
333
通过原型新增方法
在原型对象上新增实例对象需要的方法
var fn1 = function() {
this.foo = function() {
console.log(11111)
}
}
let f1 = new fn1()
var fn2 = function() {}
fn2.prototype.foo = function() {
console.log(11111)
}
let f2 = new fn2()
1