内存
内存用于暂时存放CPU中的运算数据,与硬盘等外部存储器交换的数据。是外存与CPU进行沟通的桥梁
V8
-
V8 是一款主流的JavaScript执行引擎
-
采用即时编译(转为机器码),其它引擎提前转为机器吗后在执行
-
V8垃圾回收策略
- 分代回收
- 空间复制
- 标记清除
- 标记整理
- 标记增量
内存管理
-
内存:由可读写单元组成,表示一片可操作空间,我们平常创建基本类型,对象,数组等都需要内存。既然有使用就会有管理。js中的内存管理分为三步:1. 申请内存空间, 2. 使用内存空间,3. 释放内存空间。
在 js 中,不能像c和c++ 主动调用api 来管理
let obj = {} 赋值 自动会分配一块内存
obj.name="lg" 使用空间
obj = null; 释放内存
可达对象
-
可以访问到的对象就是可达对象 (引用,作用域链)
-
可达的标准就是从根出发是否能够被找到
-
js 中全局变量对象就是根 (全局上下文)
垃圾回收 简书
-
js 中内存管理是自动的
-
对象不再被引用的时候是垃圾 (通过引用关系无法找到某些对象的时候)
-
对象不能被正确访问的时候 (对象存在,因语法错误或结构错误无法找到的对象)
-
GC(垃圾回收) 算法
-
找到内存中的垃圾,并释放和回收空间
- 在运行中,上下文中不再需要时
- 在代码中,外部环境找不到对象时
-
常见GC算法
-
引用计数
-
给每个对象添加一个引用计数器,标识对象的引用次数,当一个新引用指向对象时计数器加1,当指向对象的引用失效时计数器减1,当计数器为0时会被立即回收
-
优点:
- 立即回收
- 最大限度减少程序暂停
-
缺点:
- 无法回收循环引用的对象
function fn() { const obj1 = {} const obj2 = {} //全局作用域下找不到obj1,obj2,但是obj1.name,obj2.name还引用着,所以引用数不为0 obj1.name = obj2; obj2.name = obj1 return 'xxxx' } fn()
- 时间开销大(维护数值变化(监听),对象修改,引用计数也需修改)
-
-
标记清除
-
分标记和清除两个阶段完成
-
遍历所有对象找标记活动对象
- 标记计数时会递归的查找引用层级关系,把可达对象进行标记
-
遍历所有对象清除没有标记对象
-
清除没有标记的对象
-
标记清除将回收的空间放在空闲列表上面,方便后面的程序直接在这里申请内存使用。
-
-
回收相应空间
-
优点
- 解决对象循环引用不能回收的问题(相对于引用计数)
-
缺点
- 空间碎片化(由于回收的空间地址不连续),不能是空间最大化使用
- 不会立即清除垃圾
-
-
标记整理
- 标记整理算法是标记清除算法的一个升级。主要是为了减少碎片空间化。工作原理与标记清除算法相同。
- 相比于标记清除,在清除没有标记的对象之前,把这些垃圾对象移动位置,也就是先进行整理到一块后再清理,这样减少了碎片化空间
-
分代回收
-
内存设限:64位内存不超过1.5G,32位不超过800m
-
内存空间分为 新生代(存活时间短)和老生代
-
小空间用于存储新生代对象(32m[64位] | 16m[32位])
-
新生代对象回收
-
回收过程采用复制算法+标记整理
-
新生代内存区分为二个等大小空间
-
使用空间位From,空闲空间位To
-
活动对象存储于From空间
-
标记整理后将活动对象拷贝至To
-
From 与 To交换空间完成释放
回收细节
- 拷贝过程中可能出现晋升
- 晋升就是将新生代对象移动至老生代
- 一轮GC还存活的新生代需要晋升
- To空间的使用率超过25%
-
-
老年代对象 (1.4G[64位] | 700m[32位])
- 老年代对象就是存活时间长的对象
- 主要采用标记清楚,标记整理,增量标记算法
- 首先(主要)使用标记清除完成垃圾空间的回收
- 采用标记整理进行空间优化
- 采用增量标记来进行效率优化
-
-
-
-