分享更有价值
被信任是一种快乐

Node.js中的垃圾回收机制是什么

文章页正文上

这篇“Node.js中的垃圾回收机制是什么”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来看看这篇“Node.js中的垃圾回收机制是什么”文章吧。GC,Garbage Collection,垃圾回收。在编程中,一般指的是内存自动回收机制,会定时将不需要用到的数据进行清除。Node.js 底层使用了 V8 引擎。V8 是 Google 开源的一款高性能 JavaScript 引擎,使用了 C++ 进行编写。Node.js 的内存主要分成三部分:代码空间:存放代码段的地方;栈:函数调用栈产生的临时变量,为一些基本类型,比如数字、字符串、布尔值,以及对象引用(保存的是地址,不保存对象本身)。堆:存放对象等数据。Node.js 底层使用的是 V8,下面讲解一下 V8 的内存回收机制。首先 JS 中所有的对象都会保存在堆内存中。在创建进程的时候,会分配一个初始大小的堆内存,然后我们的对象就会放到里面。当对象越来越多,堆内存会不够用,此时堆内存会动态地扩大。如果到达一个最大限制(现在通常是 4GB),就会堆内存溢出的错误,然后终止 Node.js 进程。V8 首先将内存分成两部分,或者说两个生代(generation):新生代(yong generation):保存一些存活时间较短的对象;老生代(old generation):保存存活时间长或者长驻的对免费云主机、域名象。新生代很小,这里会存放一些存活时间很短的对象,通常它们会被频繁地回收(比如函数的调用栈的一些临时对象)。新生代可通过 node --max-semi-space-size=SIZE index.js 修改新生代的大小,单位为 MB。另外,老生代则通过 --max-old-space-size=SIZE 来设置新生代使用了 Scavenge 算法,是一种基于 copy(复制)的算法。新生代会分成两个空间,这种空间称为 semispace,它们为:From 空间:新声明的对象会放入这里To 空间:用作搬移的空间新声明的对象会放入到 From 空间中,From 空间的对象紧密排布,通过指针,上一对象紧贴下一个对象,是内存连续的,不用担心内存碎片的问题。所谓内存碎片,指的是空间分配不均匀,产生大量小的连续空间,无法放入一个大对象。当 From 空间快满了,我们就会遍历找出活跃对象,将它们 copy 到 To 空间。此时 From 空间其实就空了,然后我们将 From 和 To 互换身份。如果一些对象被 copy 了多次,会被认为存活时间较长,将被移动到老生代中。这种基于 copy 的算法,优点是可以很好地处理内存碎片的问题,缺点是会浪费一些空间作为搬移的空间位置,此外因为拷贝比较耗费时间,所以不适合分配太大的内存空间,更多是做一种辅助 GC。老生代的空间就比新生代要大得多了,放的是一些存活时间长的对象,用的是 Mark-Sweep (标记清除)算法。首先是标记阶段。从根集 Root Set(执行栈和全局对象)往上找到所有能访问到的对象,给它们标记为活跃对象。标记完后,就是清除阶段,将没有标记的对象清除,其实就是标记一下这个内存地址为空闲。这种做法会导致 空闲内存空间碎片化,当我们创建了一个大的连续对象,就会找不到地方放下。这时候,就要用 Mark-Compact(标记整理)来将碎片的活跃对象做一个整合。Mark-Compact 会将所有活跃对象拷贝移动到一端,然后边界的另一边就是一整块的连续可用内存了。考虑到 Mark-Sweep 和 Mark-Compact 花费的时间很长,且会阻塞 JavaScript 的线程,所以通常我们不会一次性做完,而是用 增量标记 (Incremental Marking)的方式。也就是做断断续续地标记,小步走,垃圾回收和应用逻辑交替进行。另外,V8 还做了并行标记和并行清理,提高执行效率。我们可以通过 process.memoryUsage 方法拿到内存相关的一些信息。

process.memoryUsage();

输出内容为:

{
rss:35454976,
heapTotal:7127040,
heapUsed:5287088,
external:958852,
arrayBuffers:11314
}

说明

说明
rss:常驻内存大小(resident set size),包括代码片段、堆内存、栈等部分。heapTotal:V8 的堆内存总大小;heapUsed:占用的堆内存;external:V8 之外的的内存大小,指的是 C++ 对象占用的内存,比如 Buffer 数据。arrayBuffers:ArrayBufferSharedArrayBuffer 相关的内存大小,属于 external 的一部分。以上数字的单位都是字节。写一个脚本,用一个定时器,让一个数组不停地变大,并打印堆内存使用情况,直到内存溢出。

constformat=function(bytes){
return(bytes/1024/1024).toFixed(2)+"MB";
};

constprintMemoryUsage=function(){
constmemoryUsage=process.memoryUsage();
console.log(
`heapTotal:${format(memoryUsage.heapTotal)},heapUsed:${format(
memoryUsage.heapUsed
)}`
);
};

constbigArray=[];
setInterval(function(){
bigArray.push(newArray(20*1024*1024));
printMemoryUsage();
},500);

需要特别注意的是,不要用 Buffer 做测试。因为 Buffer 是 Node.js 特有的处理二进制的对象,它不是在 V8 中的实现的,是 Node.js 用 C++ 另外实现的,不通过 V8 分配内存,属于堆外内存。我使用电脑是 macbook pro M1 Pro,Node.js 版本为 v16.17.0,使用的 V8 版本是 9.4.146.26-node.22(通过 process.versions.v8 得到)。输出结果为(省略了一些多余的信息):

heapTotal:164.81MB,heapUsed:163.93MB
heapTotal:325.83MB,heapUsed:323.79MB
heapTotal:488.59MB,heapUsed:483.84MB
...
heapTotal:4036.44MB,heapUsed:4003.37MB
heapTotal:4196.45MB,heapUsed:4163.29MB



[28033:0x140008000]17968ms:Mark-sweep4003.2(4036.4)->4003.1(4036.4)MB,2233.8/0.0ms(averagemu=0.565,currentmu=0.310)allocationfailurescavengemightnotsucceed
[28033:0x140008000]19815ms:Mark-sweep4163.3(4196.5)->4163.1(4196.5)MB,1780.3/0.0ms(averagemu=0.413,currentmu=0.036)allocationfailurescavengemightnotsucceed




FATALERROR:ReachedheaplimitAllocationfailed-JavaScriptheapoutofmemory
...

可以看到,是在 4000 MB 之后超出了内存上限,发生堆溢出,然后退出了进程。说明在我的机器上,默认的最大内存为 4G。

可以看到,是在 4000 MB 之后超出了内存上限,发生堆溢出,然后退出了进程。说明在我的机器上,默认的最大内存为 4G。
实际最大内存和它运行所在的机器有关,如果你的机器的内存大小为 2G,最大内存将设置为 1.5G。以上就是关于“Node.js中的垃圾回收机制是什么”这篇文章的内容,相信大家都有了一定的了解,希望小编分享的内容对大家有帮助,若想了解更多相关的知识内容,请关注云技术行业资讯频道。

相关推荐: vue严格模式启动项目报错如何解决

本篇内容介绍了“vue严格模式启动项目报错如何解决”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成! 首先,我们需要了解什么是Vue.js的严格模式。Vue.js中…

文章页内容下
赞(0) 打赏
版权声明:本站采用知识共享、学习交流,不允许用于商业用途;文章由发布者自行承担一切责任,与本站无关。
文章页正文下
文章页评论上

云服务器、web空间可免费试用

宝塔面板主机、支持php,mysql等,SSL部署;安全高速企业专供99.999%稳定,另有高防主机、不限制内容等类型,具体可咨询QQ:360163164,Tel同微信:18905205712

主机选购导航云服务器试用

登录

找回密码

注册