这篇文章将为大家详细讲解有关nodejs垃圾回收的案例分析,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。
nodejs的垃圾回收机制是由v8引擎自动管理的。
nodejs的内存限制
在一般的后端语言(php)来说,内存的使用上是没有限制的,但对于nodejs来说只能使用系统的部分----64位系统为1.4G,32位系统位0.7G。这时如果你要处理个3G文件进行数据分析,即使系统的内存为8G,在该nodejs进程内存还是会溢出。
造成上面这个问题主要是因为nodejs是基于v8的,nodejs是通过v8自己的方式来管理内存的。那v8为什么要限制堆内存的大小呢?原因有2:
1、表层原因:v8是为浏览器设计的,不大可能遇到大内存的情景。
2.深层原因:v8垃圾回收机制的限制。以1.5G的堆内存为例,v8做一次小的垃圾回收需要50ms,做一次非增量的垃圾回收要1s。垃圾回收时会引起js的线程的暂停,在这样的时间花销下,应用的性能、响应能力会直线下降。
内存限制是可以打开的:
--max-old-space-size(老生代)
--max-new-space-size(新生代)
v8堆内存大小 = 老生代 + 新生代
v8垃圾回收机制
v8垃圾回收主要是基于分代式垃圾回收机制。按对象的存活时间将内存的垃圾回收进行不同的分代,分别对不同的分代内存进行不同的算法。
新生代--->存活时间较短的对象
老生代--->存活时间较长或常驻内存的对象
上面也说过,nodejs堆内存的大小是新生代内存空间加上老生代内存空间。
新生代算法
新生代主要是通过scavenge算法进行垃圾回收。
这是一种采用复制的方式来实现垃圾回收,将堆内存一分为二,每个空间称为semispace。在这2个semispace空间中,只有一个处于使用中(称为from空间),另一个处于空闲中(称为to空间)。开始分配时首先从from空间开始,当开始垃圾回收时,也是从from空间开始检查存活对象,把存活对象复制到to空间,而非存活对象占用的空间就会被释放。完成复制后,from空间和to空间角色对调。
从上面的过程可以知道,scavenge的缺点就是只使用了一半的堆内存,牺牲空间获取时间。
老生代通过mark-sweep、mark-comopact算法。
mark-sweep标记清除,分为标记、清除2个阶段。mark-sweep先在标记阶段遍历堆内存中的所有对象,并标记存活的对象;在清除阶段把没有被标记的对象清除。可以看出,scavenge只复制存活的对象,mark-sweep只清理死亡的对象。因为在新生代中存活的对象占用小部分,而在老生代中死亡对象占用小部分,这是这2中算法高效的原因。
Mark-compact标记整理,mark-sweep中会出现一个问题,在回收后,对内存会出现不连续的状态(内存碎片)。内存碎片会对后续的内存分配造成影响,因为会有这样一种情况:需要分配个大内存,而所有内存碎片都无法完成分配,这会提前触发垃圾回收,而这个回收时不必要的。Mark-compact是在Mark-sweep基础上演变而来的,它主要区别在于:对象被标记后,在整理的过程中会将存活的对象都往一端移动,移动完成后直接清除。
小结:在正常的使用过程中,v8的内存限制还是够用的,但nodejs的垃圾回收、单线程还是会影响性能。想要高性能,需要让垃圾回收尽量小。在实际的开发中要老生代对象的使用,如实现web服务的会话(session),一般会通过内存来存储(数组),在访问量大的情况下会导致老生代对象剧增,有可能造成溢出。如果要处理大内存的数据,比如读取3G的文件,我们会通过可读流的pipe()方法,这样就不会受到v8内存的限制影响,提高了nodejs程序的健壮性。
关于“nodejs垃圾回收的案例分析”这篇文章就分享到这里了,希望以上内容可以对大家有一定的帮助,使各位可以学到更多知识,如果觉得文章不错,请把它分享出去让更多的人看到。
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。