Node 内存泄露
云积分大前端团队 人气:01、node内存相关知识
无论是运行在浏览器端的js,还是运行在node中的js,关于内存管理的方案,都是通过垃圾回收机制来实现内存的分配和释放。当我们的代码编写有缺陷时,可能就无法通过gc来释放内存,这个时候,我们就造成了内存泄露。
Node.js进程的内存管理,都是由 V8 引擎自动处理的,包括内存的分配和释放。V8 自动处理内存的分配和释放,叫垃圾回收机制(gc)。
垃圾回收机制,解决了大部分内存管理的问题,但是并不意味着内存泄露的问题就不存在。在一些特殊的场景下,会发生内存泄露。
垃圾回收机制,是根据root对象(window/global)依次梳理对象的引用,如果能从root的引用链到达访问,V8就会将其标记为可到达对象,反之为不可到达对象。被标记为不可到达对象(即无引用的对象)后就会被 V8 回收。
2、哪些情况会造成内存泄露
第一、全局变量
全局变量会直接挂在root对象上,不会被清除掉。只要一个变量挂载到root对象上,自程序运行起,它就会一直占据着内存空间。
第二、函数闭包
闭包会引用父级函数的变量,如果闭包未释放,就会导致内存被持续占用,从而导致内存泄露。
在实际的业务场景中,引用的变量极有可能是挂载到从root可以追溯到的对象上,导致的内存泄露。
第三、事件监听
多次的重复的事件监听,可以导致内存泄露的问题。
3、内存泄露的监测
node的内存泄露监测,基本原理如下,
在node中,有专门进行内存监测的工具——heapdump。
heapdump,是一个npm包,使用比较简洁的语法,就能生成内存快照文件。
内存快照文件,是以heapsnapshot为扩展名的一种文件,该文件记录了关于内存使用的基本情况。
Chrome devTools作为一种工具,可以对内存快照文件,进行分析。
一段监测内存变化的代码如下:
const EventEmitter = require('events'); const heapdump = require('heapdump'); global.test = new EventEmitter(); heapdump.writeSnapshot('./' + Date.now() + '.heapsnapshot'); function run3() { const innerData = new Buffer(100); const outClosure3 = function () { void innerData; }; test.on('error', () => { console.log('error'); }); outClosure3(); } for(let i = 0; i < 100; i++) { run3(); } // run3(); // gc(); heapdump.writeSnapshot('./' + Date.now() + '.heapsnapshot');
其中,heapdump.writeSnapshot方法,就是生成内存快照文件的方法。
我们使用node的方式,进行执行,就会生成两个heapsnapshot文件。
4、Chrome DevTools进行分析和对比
在Chrome DevTools => Memory => Profiles中,加载生成的两个heapsnapshot文件。
如下图所示,可以查看相应的内存占用情况:
- Summary:以构造函数名分类显示。
- Comparison:比较多个快照之间的差异。
- Containment:查看整个GC路径。
- Statistics:以饼状图显示内存占用信息。
再看Statistics中关于内存占用的占比分析:
再看Comparison中对比多个快照之间的差异。(可以很明显的看出增加的部分)
5、内存分析的意义
从商业的角度来说,有时候我们无法通过代码,直观的看到内存泄露相关的信息,而这种内存分析的方式,给了我们解决问题的思路。
在现代化的业务开发中,内存监测是一种必要的工具,掌握了基本的原理,有助于我们分析和理解node性能分析的平台型工具。更有助于我们对node的理解。
加载全部内容