13 | 垃圾回收:垃圾数据是如何自动回收的?
13 | 垃圾回收:垃圾数据是如何自动回收的?
讲述:李兵
时长14:36大小20.02M
不同语言的垃圾回收策略
调用栈中的数据是如何回收的
堆中的数据是如何回收的
代际假说和分代收集
垃圾回收器的工作流程
副垃圾回收器
主垃圾回收器
全停顿
总结
思考时间
赞 52
提建议
精选留言(86)
- mfist2019-09-031. 如何判断内存泄漏的?一般是感官上的长时间运行页面卡顿,猜可能会有内存泄漏。通过DynaTrace(IE)profiles等工具一段时间收集数据,观察对象的使用情况。然后判断是否存在内存泄漏。修改后验证 2. 工作中避免内存泄漏方法:确定不使用的临时变量置为null,当前es6普及场景下少使用闭包也是一种方法。 今日总结 垃圾回收策略一般分为手动回收和自动回收,java python JavaScript等高级预言为了减轻程序员负担和出错概率采用了自动回收策略。JavaScript的原始类型数据和引用数据是分别存储在栈和椎中的,由于栈和堆分配空间大小差异,垃圾回收方式也不一样。栈中分配空间通过ESP的向下移动销毁保存在栈中数据;堆中垃圾回收主要通过副垃圾回收器(新生代)和主垃圾回收器(老生代)负责的,副垃圾回收器采用scavenge算法将区域分为对象区域和空闲区域,通过两个区域的反转让新生代区域无限使用下去。主垃圾回收器采用Mark-Sweep(Mark-Compact Incremental Marking解决不同场景下问题的算法改进)算法进行空间回收的。无论是主副垃圾回收器的策略都是标记-清除-整理三个大的步骤。另外还有新生代的晋升策略(两次未清除的),大对象直接分配在老生代。展开
作者回复: 总结很好,还可以通过Chrome开发者工具中的Performance来观察。
111 - dellyoung2020-03-29栈和堆 栈垃圾回收 当函数执行结束,JS引擎通过向下移动ESP指针(记录调用栈当前执行状态的指针),来销毁该函数保存在栈中的执行上下文(变量环境、词法环境、this、outer)。 堆垃圾回收 一、代际假说 1、大部分对象存活时间很短 2、不被销毁的对象,会活的更久 二、分类 V8 中会把堆分为新生代和老生代两个区域,新生代中存放的是生存时间短的对象,老生代中存放的生存时间久的对象。 三、新生代 算法:Scavenge 算法 原理: 1、把新生代空间对半划分为两个区域,一半是对象区域,一半是空闲区域。 2、新加入的对象都会存放到对象区域,当对象区域快被写满时,就需要执行一次垃圾清理操作。 3、先对对象区域中的垃圾做标记,标记完成之后,把这些存活的对象复制到空闲区域中 4、完成复制后,对象区域与空闲区域进行角色翻转,也就是原来的对象区域变成空闲区域,原来的空闲区域变成了对象区域。 对象晋升策略: 经过两次垃圾回收依然还存活的对象,会被移动到老生区中。 四、老生代 算法:标记 - 清除(Mark-Sweep)算法 原理: 1、标记:标记阶段就是从一组根元素开始,递归遍历这组根元素,在这个遍历过程中,能到达的元素称为活动对象,没有到达的元素就可以判断为垃圾数据。 2、清除:将垃圾数据进行清除。 碎片: 对一块内存多次执行标记 - 清除算法后,会产生大量不连续的内存碎片。而碎片过多会导致大对象无法分配到足够的连续内存。 算法:标记 - 整理(Mark-Compact)算法 原理: 1、标记:和标记 - 清除的标记过程一样,从一组根元素开始,递归遍历这组根元素,在这个遍历过程中,能到达的元素标记为活动对象。 2、整理:让所有存活的对象都向内存的一端移动 3、清除:清理掉端边界以外的内存 优化算法:增量标记(Incremental Marking)算法 原理: 1、为了降低老生代的垃圾回收而造成的卡顿 2、V8把一个完整的垃圾回收任务拆分为很多小的任务 1、让垃圾回收标记和 JavaScript 应用逻辑交替进行展开共 2 条评论69
- 忘忧草的约定2019-09-04老师请问:经过内存整理之后活动对象在堆中的内存地址就变化了,主线程还处于垃圾回收阶段,此时内存变化是如何更新到相应执行上下文中的呢共 6 条评论25
- ytd2019-09-04做了这么长时间的前端开发,第一次关注内存泄漏的问题,以后得多关注这方面了。通过chrome的Perfomance面板记录页面的活动,然后在页面上进行各种交互操作,过一段时间后(时间越长越好),停止记录,生成统计数据,然后看timeline下部的内存变化趋势图,如果是有规律的周期平稳变化,则不存在内存泄漏,如果整体趋势上涨则说明存在内存泄漏。另外,想问下老师,这个内存变化趋势只是js堆内存的变化吗?因为我发现在统计图表下部分了几类:JS Heap、Documents、Nodes、Listeners、GPU Memory,JS Heap是占用最多的,其次是Nodes,再次是Listeners。展开25
- 一步2019-09-03对于栈中的垃圾回收,是通过移动 ESP 指针来实现的,是不需要通过V8的垃圾回收机制的吗?
作者回复: 是的 栈中的过期数据直接通过esp给抹掉,效率非常高。
共 3 条评论21 - Hurry2019-09-03使用 chrome 的 Performance 面板,观察内存变化 如何多次垃圾回收后,整体趋势是向上,就存在内部泄漏的可能!
作者回复: 这是一个很好的方法
共 3 条评论21 - 一步2019-09-03对于新生代,副垃圾回收器是怎么进行标记的,文章也就一句话带过了,是和老生代标记算法一样吗?从一组跟元素开始,然后开始遍历的
作者回复: 新生区和老生区标记过程是同一个过程,之后新生代把存活的数据移动到空闲区,老生代把死去的对象加到空闲列表中。
共 2 条评论18 - 芒果2019-11-06大道至简,看完了浏览器的垃圾回收,让我联想到了jvm的垃圾回收,发现2者思想上基本都差不多。
作者回复: 现代虚拟机都是抄来抄去的
16 - 屈悦微2019-12-06这篇文章写得很有深度,反复看了几遍,收获颇多,但是仍有一个问题,望作者百忙之中能解答 在本篇中作者介绍了的垃圾回收机制是,标记对象的机制 但在《javascript高级程序设计》中还介绍了引用计数的机制 我产生以下两个疑问 1.v8有没有使用引用计数的机制? 2.如果有,何时使用引用计数,何时使用标记对象?展开
作者回复: 引用计数有问题,会导致内存泄漏,所以现在流行的垃圾回收器都没有采用引用计数的方式!
16 - 郝仁杰2019-09-03trim之后,数据在堆上的地址发生变化,v8是如何更新对应栈上的引用的
作者回复: JavaScript中的原始字符串是不可变的(immutable),也就是说,一旦一个字符串创建了,它在内存中的值就不可能改变,这和其他语言是有区别的。 所以当你调用trim方法后,v8引擎返回给你的是一个新字符串,并不是之前的字符串了。
共 7 条评论14 - 咖飞的白2020-01-13请教老师几个问题: 1. JS 执行代码时是在执行声明语句时就分配内存还是赋值时分配?若是执行声明语句时就分配,那如何知道是大对象(存储在老生代)还是新对象(存储在新生代)?
作者回复: 声明变量是在编译阶段完成的,这时赋值语句还没执行! 比如 var a = 6 首先编译阶段确定有变量a了,并给a赋值undefined; 接下来执行代码,在执行过程中,会将6赋给a,这时候a等于6! 由于6是原生类型,通常情况下,会在栈上分配该变量! 如果 var a = Object 将对象赋给a时,在编译阶段 a依然等于undefined,在执行过程中,会在堆中创建一块内存,存放Object的值,然后栈中有个指向堆中Object地址的指针
13 - Jerry银银2020-01-06学Java虚拟机的垃圾回收机制,再来看这篇文章,可谓是:“天下垃圾一样收”! Java虚拟机垃圾回收使用的也是分代收集的策略,主要也是新生代和老年代。而分代收集的思想依据是二八原则:80%的对象即生即死。共 1 条评论12
- tick2019-09-03标记的过程具体是什么样的呢?我理解老师讲的是,一个指针指向堆里,每次移动一块内存,一个指针遍历栈中,然后看栈中是否引用这块堆中的内存,但感觉这样效率很低
作者回复: 比如全局window对象看成是一个树状结构,垃圾回收时,V8会先遍历这颗树,能遍历到的元素说明还存活的,标记为活动对象!没有被标记到的说明已经没有被引用了。 同时V8还维护了一个空闲列表,也就是没有被使用的空闲空间列表,垃圾清理过程就是把没有标记的添加到空闲列表中! 这样就完成了“标记-清除”操作
共 2 条评论11 - YBB2019-09-05有个问题想请教下,副回收器的触发频率会高于主回收器吗?还是两者是同步触发的?
作者回复: 会的,副垃圾回收器执行速度快,而且容易满,所以回收频率会比主垃圾回收器高。
10 - 于你2019-09-07老师,我最近听了一门课,那个老师说现代的浏览器用闭包不会造成内存泄漏,因为垃圾回收是用的标记清除
作者回复: 对,没有被引用的闭包会被自动回收,不过如果没用的闭包还保存在全局变量中,依然会内存泄漏!
共 5 条评论9 - heora2021-03-14老师,问一个问题,WeakMap 和 WeakSet 是如何被回收的?最近面试被问到这个问题,面试官说它不计入垃圾回收机制,但是不应该是都是自动进行垃圾回收的嘛?共 3 条评论8
- JC.彦2020-04-13既然v8有自动垃圾回收机制,为啥还会有内存泄露,只是闭包引起的吗?如何解决内存泄露问题? 数组占用内存过高就说明代码写的不好,这是什么原因?共 4 条评论6
- 江霖2019-12-11老师我有个问题,副垃圾回收器的回收机制是对象区域满的时候,那么主垃圾回收器呢? 代码空间占用的内存什么时间回收呢共 4 条评论5
- 韦恩先生2019-09-06增量标记会受到中间穿插的js应用逻辑影响么?会造成标记结果不全或者错误么?
作者回复: 不全没关系,新产生的垃圾下次再回收,分配内存使用空闲列表里面的。
4 - Lx2019-09-03我想问下,标记清除和标记整理是两个同等级的算法策略吗?目前v8使用的是两者结合,还是只有一种?
作者回复: 标记清除和标记整理可以看成是垃圾回收的两个阶段吧,v8在实现垃圾回收过程中,两种算法都用上了。
共 3 条评论4