1什么是垃圾数据?我们在写js代码的时候,会频繁的操作数据。当一些数据不需要时,就是垃圾数据,应该回收垃圾数据占用的内存。这段代码变量的生命周期letdog.a=newArray(1)当JavaScript执行这段代码时,会先在全局范围内添加一个dog属性,并在堆中创建一个空对象。对象的地址指向狗。然后创建一个大小为1的数组,属性地址指向dog.a。此时的内存布局图如下:如果此时我给a属性赋值另一个对象,代码如下:当堆中的数组对象变成未使用的数据时,专业术语是“无法访问”的数据。这是需要回收的垃圾数据。两种垃圾回收算法这个过程可以想象成一个巨大的油漆桶从根部溢出。它从一个根节点开始,对可达对象进行标记和着色,然后删除未标记的对象。第一步:在空格中标注“可达”值。V8使用可达性算法来确定堆中的对象是否应该被回收。这个算法的思路是这样的:从根节点(Root)开始,遍历所有对象。可以遍历的对象是可达的。没有遍历过的对象是不可达的。在浏览器环境中,有很多根节点,主要有这几种:全局变量window,位于每个iframe中;文档DOM树;存储在堆栈中的变量;...这些根节点不是垃圾,不能回收。第二步:回收“unreachable”值占用的内存。所有标记完成后,统一清理内存中所有不可达对象。第三步是整理记忆。频繁回收对象后,内存中会出现大量不连续的空间,专业术语称为“内存碎片”。当内存中出现大量内存碎片时,如果需要分配大块连续内存,可能会出现内存不足的情况。3.垃圾回收当浏览器进行垃圾回收时,会暂停JavaScript脚本,等待垃圾回收完成后再继续执行。对于普通的应用来说,这没什么问题,但是对于JS游戏和动画等对连续性要求高的,如果停顿时间长了,页面就会卡顿。这就是我们接下来要讲的垃圾回收:什么时候进行垃圾回收,可以避免长时间的停顿。所以最后一步是对内存进行碎片整理。(但这一步其实是可选的,因为有些垃圾收集器是不会产生内存碎片的,比如我们接下来要介绍的二级垃圾收集器。)分代收集浏览器将数据分为两种,一种是有“临时”对象的,一种是是“长期”的对象。临时对象:大多数对象在内存中存在的时间很短;例如在函数内部声明的变量,或块级范围内的变量。当一个函数或代码块执行时,范围内定义的变量被销毁;此类物品很快变得无法接近,应迅速回收。Long-lastingobjects:生命周期较长的对象,如全局窗口、DOM、WebAPI等;这样的物品可以慢慢回收。这两类对象对应不同的回收策略。因此,V8将堆分为两个区域:新生代和老年代。新生代存放临时对象,老年代存放持久对象。并让次垃圾收集器和主垃圾收集器分别负责新生代和老年代的垃圾收集。这可以实现高效的垃圾收集。主要垃圾收集器负责老年代的垃圾收集,有两个特点:对象占用空间大;该对象会存在很长时间。它使用“标记和清除”算法执行垃圾收集。第一个是标记。从一组根元素开始,递归遍历这组根元素;在这个遍历过程中,能够到达的元素称为活动对象,不能到达的元素可以判断为垃圾数据。然后是清除垃圾。直接清理标记为垃圾的数据。多次mark-clears后,会产生大量不连续的内存碎片,需要进行内存组织。二级垃圾收集器负责新生代的垃圾收集,通常只支持1-8M的容量。新生代分为两个区域:一般是对象区,一半是空闲区。新添加的对象放入对象区,当对象区快满时,会进行一次垃圾清理。首先标记对象区域中的所有垃圾;标记完成后,将存活的对象复制到空闲区,并有序排列;这就又回到了我们之前留下的问题——二级垃圾回收器不进行碎片整理。因为此时空闲区是有序的,没有碎片,所以不需要整理;复制完成后,对象区域将与空闲区域交换。将空闲区中存活的对象放入对象区。这样,垃圾回收就完成了。由于二级垃圾收集器运行频繁,为了执行效率,一般会把新生区的空间设置得比较小。一旦检测到空间已满,就会执行垃圾收集。一句话分代回收就是:把堆分成新生代和老年代,新生代多回收一些,老年代回收少一些。这样就减少了每次需要遍历的对象数量,从而减少了每次垃圾回收的耗时。增量收集如果脚本中的对象很多,引擎会一次遍历整个对象,造成长时间的停顿。所以引擎将垃圾收集工作分成更小的块,一次处理一部分,多次处理。这解决了长时间停顿的问题。空闲时间收集垃圾收集器只会在CPU空闲时尝试运行,以减少对代码执行的可能影响。四浏览器中不同类型变量的内存什么时候释放?Javascritp中的类型:值类型、引用类型。引用类型:在没有更多引用后由V8自动回收。值类型:如果是在闭包的情况下,会被V8回收,直到闭包没有引用为止;在非关闭的情况下,等待新一代V8切换时回收。
