NodeJs内存管理

本文作者:ivweb 王少飞 原文出处:IVWEB社区

nodejs进程内存的使用和原理

V8简介

nodejs代码的运行基于V8,就像java运行需要hotspot,php运行需要zend。V8的由来是,当年web2.0,google的很多业务都在web端,为了提升浏览器中js的执行效率,研发了V8。

V8每发布一个新的版本,nodejs就会相应的发布新版本来使用新版本的V8。

nodejs9以后的版本都是使用的V8 6.2版本。这个版本都有哪些改进:

1 性能优化

  • 1)优化了Object.prototype.toString 的性能,比之前提升了6.5倍
  • 2)优化了 ES2015 proxies 的性能, 比之前提升了5倍
  • 3)优化了 String#includes()的性能,比之前提升了3倍
  • 4)哈希查找速度更快,从而提高了Map,Set,WeakMap和WeakSet的性能
  • 5)新生代内存垃圾回收采用 Parallel Scavenger算法 2 低内存模式:semi-space为512k,低内存设备减少了发生内存不足的概率。 3 优化正则表达式规则
  • 1)支持 dotAll 模式, s匹配模式下,.可以匹配任何字符,包括转义字符
  • 2)支持 正向后瞻和负向后瞻 4 字符串的最大长度增加,从 2**28 - 16 增加到 2**30 - 25

内存限制

V8限制了nodejs每个进程的最大内存:64系统1.4G,32位系统0.7G, 这个大小的限制在chrome里面已经够用了,但在服务端nodejs感觉可能不够用。 为什么这样限制? 如果内存超过1.5G时 做一次全量垃圾回收,耗时在1秒左右,这1秒时间内,进程是暂停执行的,对于高平发,高流量的服务影响会很大。

nodejs进程内存的垃圾回收和内存泄漏

V8的GC原理

nodejs进程使用的内存主要在堆(heap)中, 垃圾回收采用分代式,分为新生代和老生代。 新生代中保存存活时间较短的对象,老生代中保存存活时间较长或常驻内存的对象。 新生代通过Parallel Scavenge算法进行垃圾回收,即并行的多线程,复制算法垃圾收集器。 原理是:将堆内存一分为二,每一部分空间称为semispace。在两个semispace空间中,只有一个处于使用状态,另一个处于闲置状态。处于使用状态的semispace空间称为from,处于限制状态的空间称为to空间。

当我们分配对象时,先是在from空间中进行分配。当from空间不够用时就处罚一次新生代的垃圾回收,此时会检查from中的存活对象,并复制到to空间中,非存活的对象会被释放。完成该复制操作后,from空间和to空间互换。此时完成新生代堆内存的一次垃圾回收。

当一个对象经过多次复制依然存活,那么它将被放到老生代内存中。

老生代内存垃圾回收采用 Mark-sweep(标记清除)和Mark-Compact(标记整理), 并进行增量式垃圾回收。 和分代时垃圾回收相比,前者的空间利用率高,但效率低,由于老生代堆内存较大,一次垃圾回收会导致进程暂停时间很长,所以不会经常进行老生代垃圾回收。

实际编码中由于对变量作用域或闭包等使用不当,很可能造成内存的泄漏。在浏览器中由于页面一般情况下只加载一次,或只停留较短的时间,就算有内存泄漏也不会造成很大影响。但在服务端,就算只有一个字节的泄漏,在大量请求和高并发的请求下,泄漏会被放大,随着服务的运行时间越来越长,进程的内存占满,导致内存不足进程退出,就会会对服务器造成很大的影响。

内存泄漏和检测

nodejs内存泄漏检测工具很多,例如:v8-profiler、node-heapdump、node-mtrace、dtrace、memwatch-nenxt。 拿 memwatch-next 举例,使用方法如下:

1 安装 npm i memwatch-next 2 项目代码中:

const memwatch = require('memwatch-next');
memwatch.on('leak', info => {
    reportLogFun(`[leak-${process.pid}]${JSON.stringify(info)}`)
})

memwatch.on('stats', stats => {
    reportLogFun(`[stats-${process.pid}]${JSON.stringify(stats)}`)
})

const md = new memwatch.HeapDiff();
    // .... 业务逻辑代码
const diff = md.end();
reportLogFun(JSON.stringify(diff));

3 收集上报结果 status事件的触发条件是:进行全堆垃圾回收

[stats-3974]{"num_full_gc":16,"num_inc_gc":67155,"heap_compactions":16,"usage_trend":0.1,"estimated_base":7547592,"current_base":7577952,"min":7032208,"max":7610240}

上面的日志表示:进行了16次全堆垃圾回收,进行了67155次增量垃圾回收,进行了16次老生代堆内存整理。

leak时间的触发条件是:进行5次全堆垃圾回收后,内存没有得到释放,产生内存泄漏。

[leak-3974]{"growth":268816,"reason":"heap growth over 5 consecutive GCs (8h 52m 2s) - 29.6 kb/hr"}

上面的日志表示:进行了5次全堆垃圾回收后内存增长了268816 bytes,每小时增加29.6 kb。

diff数据暂时没有收集到数据,根据官方的介绍

意思是,从md初始化开始,到md.end()这段时间内,内存增加了多少,change>details 就是需要关注的内容,增加的最多的就是内存泄漏所在。

参考文献

https://v8project.blogspot.com/2017/09/v8-release-62.html https://bugs.chromium.org/p/chromium/issues/detail?id=738865 http://www.jianshu.com/p/4129a3fce7bb http://book.51cto.com/art/201107/278917.htm https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy https://tc39.github.io/proposal-template-literal-revision/ https://ponyfoo.com/articles/investigating-performance-object-prototype-to-string-es2015 https://zhuanlan.zhihu.com/p/27509546

原创声明,本文系作者授权云+社区发表,未经许可,不得转载。

如有侵权,请联系 yunjia_community@tencent.com 删除。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏ml

linux下如何优雅的挂载一个外界设备(比如优盘)

        最近从事linux,实验室一个破服务器,能连上网,但是输入这样的命令:        yum -y install gcc yum -y in...

39060
来自专栏xingoo, 一个梦想做发明家的程序员

Java堆外内存之突破JVM枷锁

对于有Java开发经验的朋友都知道,Java中不需要手动的申请和释放内存,JVM会自动进行垃圾回收;而使用的内存是由JVM控制的。 那么,什么时机会进行垃圾...

35890
来自专栏北京马哥教育

tomcat调优之启动参数

Linux系统中tomcat的启动参数 export JAVA_OPTS="-server -Xms1400M -Xmx1400M -Xss512k -XX:+...

388100
来自专栏码代码的陈同学

JVM内存管理

Java内存管理是一项持续的挑战,同时也是锻造出可拓展应用的必备技能。本质上,Java内存管理就是一个为新对象分配内存和释放无用对象内存的过程。

53680
来自专栏小勇DW3

常用的JVM调优参数总结汇总【随时查阅学习】

表示设置JVM启动内存的最大值为20M,必须以M为单位。将-Xmx和-Xms设置为一样可以避免JVM内存自动扩展。大的项目-Xmx和-Xms一般都要设置到10G...

1.6K50
来自专栏无题

GC优化案例3:CMS Remark之前强制minorGC

对GC优化的案例进行的系列总结(三): 请求高峰期发生GC,导致服务可用性下降 确定目标 GC日志显示,高峰期CMS在重标记(Remark)阶段耗时1.39s...

48430
来自专栏Linyb极客之路

JVM系列三:JVM参数设置、分析

不管是YGC还是Full GC,GC过程中都会对导致程序运行中中断,正确的选择不同的GC策略,调整JVM、GC的参数,可以极大的减少由于GC工作,而导...

49860
来自专栏小灰灰

jvm调优的工具介绍

jvm调优实战笔记之基础知识简介 I. 背景 java后端,提供了一个svg渲染的服务,在qps较大时,会出现频繁的gc,而此时的服务器性能本身并没有达到瓶颈...

56870
来自专栏猿人谷

Java性能调优

一、JVM内存模型及垃圾收集算法  1.根据Java虚拟机规范,JVM将内存划分为: New(年轻代) Tenured(年老代) 永久代(Perm)   其中N...

314110
来自专栏精讲JAVA

周末福利大放送,免费领取付费星球;jvm研究所的入场券,先到先得

知道各位周六日不太爱看文章,哈哈,小编周末也不想写文章,所以,我就把这周的几个星球里面出现的问题贴出来吧 Q1 Action:项目部署到生产环境中用...

36270

扫码关注云+社区

领取腾讯云代金券