当前位置: 首页 > Web前端 > vue.js

前端面试常题:JS垃圾回收机制

时间:2023-04-01 12:39:53 vue.js

摘要:众所周知,应用程序在运行过程中需要占用一定的内存空间,而在运行之后,必须释放不再使用的内存,否则将发生以下情况。图中内存占用的不断增加,一方面会影响程序的运行速度,另一方面,严重的话会导致整个程序崩溃。众所周知,应用程序在运行过程中需要占用一定的内存空间,而不再使用的内存在运行后必须释放。否则下图中的内存占用会不断增加。一方面会影响程序的运行速度,另一方面严重的话还会导致整个程序崩溃。JavaScriptMemory中的内存管理:由可读和可写单元组成,代表一块可操作空间;管理:人为操作一块空间的申请、使用和释放;内存管理:开发者主动申请空间、使用空间、释放空间;管理流程:application-use-release有些语言(比如C语言)需要手动释放内存,但是会很麻烦,所以很多语言,比如JAVA,都会提供自动内存管理机制,叫做“垃圾回收”机制”,JavaScript语言也提供了垃圾收集机制(GarbageCollection),简称GC机制。句号(StopTheWorld)在介绍垃圾回收算法之前,我们先来了解一下“句号”。在执行垃圾回收算法之前,需要暂停应用逻辑,执行完垃圾回收之后再执行应用逻辑。这种行为称为“StopTheWorld”。例如,如果GC耗时50ms,则应用程序逻辑将暂停50ms。全暂停的目的是解决应用逻辑和垃圾收集器看到的不一致的问题。比如在食堂吃饭,兴高采烈地取了菜回来,结果发现餐具已经被服务员收走了。在这里,服务员就像一个垃圾收集器,餐具就像一个分配的对象,我们就是应用逻辑。在我们看来,这只是一个临时的餐具,但服务员似乎认为你不需要使用它,所以就把它拿走了。你和服务员对同一件事看到的不一致,导致服务员做出了我们没有预料到的事情。因此,为了避免应用程序逻辑与垃圾收集器看到的不一致,垃圾收集算法需要在应用程序逻辑执行时停止它。JavaScript中的垃圾回收JavaScript在以下几种情况下会被判断为垃圾:对象不再被引用;无法从根访问该对象;GC算法常见的GC算法如下:引用计数标记清除标记排序分代回收早期引用计数浏览器最常用的垃圾收集方法称为“引用计数”(referencecounting):语言引擎有一个“引用表”它将所有资源(通常是各种值)的引用计数存储在内存中。如果一个值的引用计数为0,则表示该值不再被使用,可以释放内存。constuser1={age:11}constuser2={age:22}constuser3={age:33}constuserList=[user1.age,user2.age,user3.age]上面的代码,执行一次的时候,user1,user2,user3都被userList引用,所以它们的引用计数不为零,不会被回收完成后,num1和num2为局部变量。执行后,它们的引用计数将为零,所有此类代码将被视为“垃圾”并被回收。引用计数算法有个大问题:循环引用函数objGroup(obj1,obj2){obj1.next=obj2obj2.prev=obj1return{o1:obj1,o2:obj2,}}letobj=objGroup({name:'obj1'},{name:'obj2'})console.log(obj)在上面的例子中,obj1和obj2通过各自的属性互相引用,而且它们的引用计数都不为0,所以不会是垃圾回收机制循环,造成内存浪费。其实引用计数算法也有一个比较大的缺点,就是我们需要单独拿出一个空间来维护每个变量的引用计数。对于比较大的程序来说,空间开销还是比较大的。引用计数算法的优点:当引用计数为零时,立即发现垃圾;尽量减少程序暂停;引用计数算法的缺点:不能回收循环引用的对象;空间开销比较大;Mark-Sweep核心思想:divide标记和清除分两个阶段进行。遍历所有对象,找到标记的活动对象;遍历所有对象,清除未标记的对象;回收相应的空间。标记清除算法的优点是:与引用计数算法相比,标记清除算法最大的优点是可以回收循环引用的对象,也是v8引擎使用最多的算法。标记清除算法的缺点是:我们在上图中可以看到,红色区域是根对象,是一个全局变量,会被标记;而蓝色区域是未标记的对象,会被回收机制回收。这时候,就会出现问题。从表面上看,蓝色区域已经开垦了三个空间,但这三个空间是不连续的。当我们有一个对象需要三个空间时,那么我们刚刚回收的空间就无法分配,这就是“空间碎片”。标记-压缩(Mark-Compact)为了解决内存碎片问题,提高内存的利用率,引入了标记-压缩算法。标记清理可以看作是标记去除的增强。标记阶段的操作与标记和清除相同。清理阶段会先进行整理,移动对象位置,将幸存的对象移到一边,然后清理结束边界外的内存。标记排序的缺点是:移动对象的位置,对象不会立即被回收,回收效率比较慢。增量标记(IncrementalMarking)为了减少全停顿的时间,V8对标记进行了优化,将一次停顿的标记过程分成了很多小步骤。每一个小步骤执行完后,再让应用逻辑执行一段时间,这样交替多次后标记就完成了。长时间的GC会导致应用程序挂起并变得无响应,从而导致糟糕的用户体验。自2011年以来,v8已将“完全暂停”标志替换为增量标志。改进后的打标方式,最大停顿时间减少到原来的1/6。v8引擎垃圾回收策略采用了分代回收的概念;内存分为新生代和老年代;针对不同的对象采用不同的算法:(1)新生代:对象的生存时间更短。新鲜对象或只经过一次垃圾收集的对象。(2)OldGeneration:对象存活时间更长。经过一次或多次垃圾收集的对象。V8堆的空间等于新生代空间加上老年代空间。并且对于不同的操作系统,空间受内存限制。对于浏览器来说,这样的内存足够用了。限制内存的原因:经过不断测试浏览器的GC机制,如果内存设置的大一些,GC回收时间会达到用户的感知,会造成感知滞后。Reclaimingobjectsinthenewgeneration回收新生代对象主要采用复制算法(Scavenge算法)和标记排序算法。Scavenge算法的具体实现主要使用Cheney算法。Cheney算法将内存分成大小相等的两个空间,已用空间为From,空闲空间为To。检查From空间中的存活对象。如果对象是存活的,检查对象是否满足提升条件。如果满足条件,则提升到老年代。否则,对象将从From空间复制到To空间。如果对象不是活体,则释放非活体对象的空间。复制完成后,翻转From空间和To空间的角色。对象提升机制在一轮GC中还活着的新生代需要提升。当一个对象从From空间复制到To空间时,如果To空间使用率超过25%,该对象将直接提升到老年代。之所以设置比例为25%,是因为当Scavenge回收完成后,To空间会翻转到From空间,对象内存的分配会继续进行。如果比例过大,会影响后续的内存分配。老年代对象的回收老年代对象的回收主要采用标记清除、标记排序和增量标记算法。主要使用标记清除算法,标记清除算法只有在内存分配不足的时候才使用。首先,使用标记清除完成垃圾空间的回收;使用标记排序优化空间;使用增量标记来优化效率;新生代和老年代回收对比新生代是因为新生代占用空间小,采用空间换时间的机制。老年代区的空间比较大,不适合大量的复制算法和标记排序,所以最常用的是标记清除算法,为了尽量减少全停顿的时间。内存泄漏识别方法我们先来写一段消耗内存的代码:click利用浏览器的Performance监听内存变化点击记录,然后我们操作消耗性能的操作。操作完成后,点击停止,停止录制。然后我们看看那些导致内存泄漏的地方,我们只需要关注内存即可。可以看到内存在短时间内消耗得比较快,掉落的小凹槽说明浏览器正在进行垃圾回收。性能优化1.避免使用全局变量全局变量会挂载在window下;全局变量至少有一个引用计数;全局变量存活时间更长,继续占用内存;在数据范围明确的情况下,尽量使用局部变量;2.Reduce判断级别functiondoSomething(part,chapter){constparts=['ES2016','Engineering','Vue','React','Node']if(part){if(parts.includes(part)){console.log('属于当前课程')if(chapter>5){console.log('您需要提供VIP身份')}}}else{console.log('请确认模块信息')}}doSomething('Vue',6)//降低判断级别functiondoSomething(part,chapter){constparts=['ES2016','Engineering','Vue','React','Node']if(!part){console.log('请确认模块信息')return}if(!parts.includes(part))returnconsole.log('属于当前课程')if(chapter>5){console.log('Youneedtoprovidevipstatus')}}doSomething('Vue',6)3.减少数据读取次数对于经常使用的数据,我们需要缓存数据。

4.减少循环中的活动bodyvartest=()=>{varivararr=['HelloWorld!',25,'七月没有衣服,我和儿子一样的袍子']for(i=0;i{varivararr=['HelloWorld!',25,'齐说没穿衣服,和儿子一样的袍子']varlen=arr.lengthfor(i=0;i
  • HelloWorld!
  • 25
  • 据说没有衣服,和你同袍
  • 6.避免闭包陷阱click