内存管理
申请内存空间
使用内存空间
释放内存空间
垃圾回收
js中内存管理是自动的
对象不再被引用的时候会被认为是垃圾
对象不能从根上访问到时会被认为是垃圾
js中的可达对象:
可以访问到的对象就是可达对象
可达的标准就是从根出发是否能够被找到
JS中的根可以理解为是全局变量
GC算法
GC就是垃圾回收
GC算法:
GC是一种机制,垃圾回收器完成具体的工作。工作内容就是查找垃圾,释放其所占空间,回收空间。算法就是在工作时查找和回收所遵循的规则
常见的GC算法:
引用计数
标记清除
标记整理
分代回收
引用计数算法
原理:是设置引用数,判断当前引用数是否为0
引用计数器
引用关系改变时修改引用数字,引用数字为0是会被立即回收
引用计数算法的优缺点
优点:1、发现垃圾时立即回收。2、最大限度减少程序暂停
缺点:1、无法回收循环引用的对象。2、时间开销大
缺点案例:
ceshi函数执行完毕之后,obj1与obj2虽然在全局作用域中找不到了,但是obj1与obj2中存在相互引用,此时obj1与obj2的引用数并不是0。
function ceshi() {
const obj1 = {}
const obj2 = {}
obj1.name= obj2;
obj2.name = obj1;
return '哈哈'
}
ceshi()
标记清除算法
原理
该算法的垃圾回收原理:一共分为两个阶段分别是标记和清除。首先先去遍历所有的对象找标记活动对象。紧接着遍历所有对象去清除没有标记的对象。
图中在全局作用域(global)中是可以找到A、B、C三个对象的(A、B、C会被标记),其中A和C引用了D和E(那么D和E也会被标记)。类似的情况都是采用递归的方式去寻找一个对象是否引用了别的对象。
右边的a1和b1虽然他们之间存在相互引用,但是a1和b1是处在局部作用域中,一旦局部作用域执行完毕之后,局部作用域所占的空间就会被回收。在全局作用域(global)中是找不到a1和b1的,此时a1和b1不会被标记。GC在工作的时候,就会把a1和b1当做垃圾给清除掉。
标记清除算法的优缺点
优点:可以清除局部作用域中存在的相互引用的变量所占的内存空间,因为在局部作用域执行完毕之后,在全局window对象身上找不到局部作用域中的变量了,所以他们不会被标记。(一句话说明:解决循环引用不能被回收的问题)
缺点:会产生空间碎片化问题,使得空间不能被最大化的使用
空间碎片化的解释
如图所示:从根对象往下找可以找到B对象,所以B会被标记。A和C不会被标记。A和C会被回收,其中A占了2个字节的空间,C占了1个字节的空间, 回收的A和C的空间会被放在空闲链表中等待被程序的申请使用。
此时因为A和C被B分割着(在内存中A和C的地址不连续),A和C释放的内存空间是分散不连续的(一个2字节和一个1字节的空间,而不是一个完整的3字节空间),假如有个1.5字节的空间要被申请使用,对于A释放出的空间来说是够的,对于C释放的空间来说是不够的。这就是空间碎片化、
标记整理算法
原理
可以看成加强版的标记清除,其标记阶段的操作与标记清除一致,不同的是在清除阶段,会先执行整理,移动对象在内存中的位置,以此来达到对象在内存地址中的连续。