retech-fe / fe-interview-questions

0 stars 0 forks source link

你真的了解垃圾回收机制吗 #4

Open zuopf769 opened 1 year ago

zuopf769 commented 1 year ago

什么是垃圾回收机制?

垃圾是怎样产生的?

为什么要进行垃圾回收?

垃圾回收是怎样进行的?

V8 引擎对垃圾回收进行了哪些优化?

zuopf769 commented 1 year ago

可达对象?活动对象?非活动对象?

引用计数算法需要程序员开发时主动把需要垃圾回收的值置为null? 引用计数算法为啥发生循环引用时会发生内存溢出? 引用计数算法啥时候触发垃圾回收?是有一个变量的引用计数为0就开始垃圾回收么? 请用一个案例描述下引用计数算法? 引用计数算法的优缺点?

标记清除算法解决引用计算算法的什么问题? 标记清除算法是标记活动对象还是非活动对象? 标记清除算法是分为标记和清除两个阶段么? 标记清除算法清除阶段是立刻发生么? 清除的时候会阻塞js主线程么? 标记清除算法优缺点? 什么叫内存碎片?

现在大多数浏览器都是基于标记清除算法么?引用计数算法不用了么?

分代式垃圾回收为了解决什么问题? 为什么要分老生代和新生代两个内存空间?为啥需要分代式? v8的内存分布图? v8最多占多少内存?能修改么?怎么修改?

老生代占多少内存空间?新生代占多少内存空间?为什么这么分配? 老生代为啥要一分两半?不浪费么? 清除垃圾消耗多少时间呀一般? 把内存从使用区拷贝到空闲区效率高么? 把内存从使用区拷贝到空闲区是先拷贝在清除么,还是清除了再拷贝? 拷贝的时候就是触发垃圾回收的时候么? 什么时候晋升到老生代?

老生代为啥不采用使用区和空闲区这中策略? 标记算法只有一个根么?还是一组根?

全停顿标记法有什么缺陷? 垃圾回收是单线程么?还是多线程执行 整量标记解决什么问题? 惰性清理是什么? 增量标记每次都需要才最初的根开始么?怎么记住上次到哪儿了? 为什么会有三色标记法?哪三种颜色?

zuopf769 commented 1 year ago

https://juejin.cn/post/6981588276356317214#heading-6

zuopf769 commented 1 year ago

新生代标记清除

当开始进行垃圾回收时,新生代垃圾回收器会对使用区中的活动对象做标记,标记完成之后将使用区的活动对象复制进空闲区并进行排序,随后进入垃圾清理阶段,即将非活动对象占用的空间清理掉。最后进行角色互换,把原来的使用区变成空闲区,把原来的空闲区变成使用区

zuopf769 commented 1 year ago

新生代标记清除

首先新生代分使用区和空闲区,当使用区快满了,就要开始GC了

然后开始对使用区做标记,标记后复制一份活动对象到空闲区(这里做了整理的操作,也就是排序,避免内存碎片) 再然后清除使用区数据对象,把原来的使用区改称空闲区,把原来的空闲区改成使用区,这样的话新使用区就是空的,继续存数据,当快存满了开始下一轮GC

再看第二轮GC,还是重复上面的步骤,先标记,再把活动对象从使用区复制到空闲区,这个时候假如发现了上次就存在的对象这次还是活动对象,那这个对象就会被晋级,扔到老生代里去。接着说复制之后,使用区又被清空了,并且再次和空闲区转换,那每一轮GC过后,使用区就会变成空的

zuopf769 commented 1 year ago

分代式垃圾回收机制为了解决什么问题?

如果垃圾清理算法在每次垃圾回收时都要检查内存中所有的对象的话,对于一些大、老、存活时间长的对象来说同新、小、存活时间短的对象一个频率的检查很不好,

因为前者需要时间长并且不需要频繁进行清理,后者恰好相反,怎么优化这点呢?所以分代式就来了

分代式机制把一些新、小、存活时间短的对象作为新生代,采用一小块内存频率较高的快速清理,而一些大、老、存活时间长的对象作为老生代,使其很少接受检查,新老生代的回收机制及频率是不同的,可以说此机制的出现很大程度提高了垃圾回收机制的效率

zuopf769 commented 1 year ago

新生代什么时候晋升到老生代?

新加入的对象都会存放到使用区,当使用区快被写满时,就需要执行一次垃圾清理操作

当开始进行垃圾回收时,新生代垃圾回收器会对使用区中的活动对象做标记,标记完成之后将使用区的活动对象复制进空闲区并进行排序,随后进入垃圾清理阶段,即将非活动对象占用的空间清理掉。最后进行角色互换,把原来的使用区变成空闲区,把原来的空闲区变成使用区

当一个对象经过多次复制后依然存活,它将会被认为是生命周期较长的对象,随后会被移动到老生代中,采用老生代的垃圾回收策略进行管理

另外还有一种情况,如果复制一个对象到空闲区时,空闲区空间占用超过了 25%,那么这个对象会被直接晋升到老生代空间中,设置为 25% 的比例的原因是,当完成 Scavenge 回收后,空闲区将翻转成使用区,继续进行对象内存的分配,若占比过大,将会影响后续内存分配

zuopf769 commented 1 year ago

老生代为什么不采用新生代的分区策略?

对于大多数占用空间大、存活时间长的对象会被分配到老生代里,因为老生代中的对象通常比较大,如果再如新生代一般分区然后复制来复制去就会非常耗时,从而导致回收执行效率不高,所以老生代垃圾回收器来管理其垃圾回收执行,它的整个流程就采用的就是标记清除算法

一般50M的内存复制到另外一个空间需要20毫秒,用户不会有感知,如果老生代也采用复制的话,明显起不到空间换时间的优势

zuopf769 commented 1 year ago

V8对GC的优化都做了些什么