:说说垃圾回收机制。:嗯,垃圾收集是自动的。基本概念GC(Garbagecollection)垃圾回收机制。目的是让解释器识别需要回收的内容。当口译员认为占用房屋的人没有存在的意义时,会自动收回房屋重新出租(available)。JS和PY都选择不信任程序员,选择自己操作内存问题。节点对象都分配在堆内存上。V8主要将内存分为new-space和old-space。64位系统对应大小约为32MB和1400MB(32位系统对应一半)。两者一起构成了Node的总内存(约1.4G)。新生代空间中的对象生命周期比较短,容量比较小,而老年代空间中的对象都是“硬派”,生命力比较强,容量比较大。Node又不是HipHop,为什么要把记忆分“new-school”和“old-school”?,因为在实际情况下,各种垃圾回收策略并不能满足不同对象生命周期长度的问题,而只是对特定的情况非常有用,所以根据分代策略,它可以周期不同,选择最合适的算法策略用于有效的垃圾收集。Node针对两个不同代的不同垃圾回收策略构成了整个Node垃圾回收机制。下面详细介绍一下这两代人是如何对待辣子鸡的。New-space和ScavengeAlgorithms回顾new-space的特点:对象的生命周期一般比较短。这意味着“顽固”的对象变少了。Scavenge策略将新空间划分为两个“simispaces”(半空间),一个称为Fromspaceinuse,一个称为idleTOspace。整个回收过程如下图所示:引用计数和闭包那么在新生代中,如何让GC知道一个对象已经没有价值,也就是这个对象的生命周期结束了呢?引用计数:所谓引用计数就是跟踪记录每个值被引用的次数。当我们创建一个变量并为该变量分配一个引用类型时,那么被引用对象的引用计数就会加一。如果同一个变量被赋值给另一个变量,则计数再次加1。反之,如果给一个值为引用类型的变量赋另一个值,则原引用类型的计数会相应减一,或者当函数执行时,函数在执行过程中创建的作用域会被销毁,同时函数作用域内声明的局部变量对应的内存空间的引用计数减1。如果没有关闭,就会触发下一次垃圾回收机制,此时作用域中变量对应的空间结束声明循环。像下面的代码:functioncallOnce(){letlocal={}letfoo={}letbar={a:{},b:{}}}所以所谓的闭包,一个是即将要问的面试概念清楚了:),其实就是通过函数作为参数或者返回值,让一个外层作用域想要访问内层作用域中的私有变量的一种方式functionfoo(){letlocal={a:'ray'}returnfunction(){returnlocal}}letbar=foo()上面的代码形成了一个闭包,这样一旦一个变量引用了foo函数的返回值函数,这个返回值函数就不能被释放,这也阻止了foo函数的作用域被释放,即内存不会被释放,除非没有更多的引用,才会逐渐释放。Old-space和mark-clear/mark-organize代是除new-space之外的old-space。生成的目的是针对不同的对象生命周期使用不同的回收算法。满足条件晋升到老年代的对象具有比较顽强的生命力,也就是说在老年代中,幸存的对象占据了很大的比例,新生代使用copy-based策略效率会比较差.另外,新生代一分为二的空间策略不适合存活对象较多的情况。因此,在老年代,V8采用了mark-clear和mark-organize两种方式结合的策略。标记去除分为两个步骤:标记和清除。首先遍历老年代中的所有对象,在遍历过程中为那些还活着的对象加上标记。在下一步中,那些没有被标记的对象自然会被回收。示意图如下:黑色的是没有被标记的死对象,下次会回收内存空间。这种方式会导致下一个内存中出现大量碎片,也就是内存空间不连续,在内存分配的时候面对大对象可能得不到满足,下一个垃圾回收机制就会提前启动。于是就有了另一种标记方式——整理。与mark-sweep相比,它多了一个异步排序过程,即将所有标记为alive的cashings排序到内存的一端,排序完成后直接清除另一端连续的死对象空间,如下:最后,由于mark-sorting大量的移动物体操作都是这样设计的,导致速度非常慢。大多数情况下,V8主要使用mark-clear方法。当oldgeneration空间不够给从newgeneration升上来的死忠分配空间时,就使用mark-clearV8。垃圾收集的优化将导致应用程序逻辑完全停止。在回收老年代时,V8引入了增量标记、增量排序、延迟清理等策略。中心思想是能够让垃圾回收过程不会占用太长的应用停顿时间,并提出一种类似于时间片轮换的策略,让整个过程“雨露均布”,GC工作一段时间,应用程序会执行一段时间。堆内内存和堆外内存使用process.memoryUsage()查看节点进程的内存使用情况。单位是byte{rss:22233088,heapTotal:7708672,heapUsed:5095384,external:28898}其中rss是node进程的常驻内存。V8对内存有限制,但与浏览器不同,Node不可避免地会在服务器端操作大文件流,所以有一种方法可以通过使用缓冲区进行堆外内存分配来摆脱V8的内存限制。如下代码:letshowMem=()=>{letmem=process.memoryUsage()//process.memoryUsage()是以字节为单位的值,转换为兆字节letformat=(byte)=>{return(byte/1024/1024).toFixed(2)+'MB'}console.log(`rss:${format(mem.rss)}\nheapTotal:${format(mem.heapTotal)}\nheapUsed:${format(mem.heapUsed)}\n外部:${format(mem.external)}`);console.log('----------------------------------');}letuseMem=()=>{letsize=20*1024*1024letarr=newArray(size)for(letindex=0;index
