未加星标

教你如何在Node.js中发现JavaScript内存泄露

字体大小 | |
[前端(javascript) 所属分类 前端(javascript) | 发布者 店小二05 | 时间 2016 | 作者 红领巾 ] 0人收藏点击收藏
介绍

几月前,我不得不调试 Node.js程序中的 内存泄漏,对此找到了很多此类的文章,但细读了一些后,还是不知所措。

这篇文章的初衷是 定位Node.js中内存泄漏的 一个简单的教程。我将介绍一简单的方法入门,(以我来看)这应该是任何内存泄漏调试的起点。对于一些情况,这方法或许并不详尽。我将附上一些你想要了解的 资源 链接。

最小化理论

javascript是一门具有垃圾回收机制的语言。因此,所有Node.js进程使用的内存将由V8 JavaScript引擎自动分配、释放。

V8如何知道何时释放内存?V8维护着一个的图,这个图始于根节点,记录 程序中所有变量 。 JavaScript有4种数据类型:Boolean, String, Number及Object。前3个是简单类型,仅由分配的变量保存(如string文本)。Object及其其它任何数据在JavaScript中皆为 Object(如数组是Object),能记录其它对象的引用。


教你如何在Node.js中发现JavaScript内存泄露

V8会周期性的遍历内存图,试图确认不再被根节点抵达的一组数据。假如无法从根节点抵达,V8会认为此数据不再被使用,随即释放内存。这个过程称为垃圾回收。

何时发生内存泄漏?

当不再需要的数据依然可从根节点抵达时, JavaScript中 就出现了 内存泄漏。V8将认为此类数据依然在使用当中,并且不会进行垃圾回收。为了调试内存泄漏,我们需要定位被错误保留的数据的位置,确保V8能够清理。

值得注意的是垃圾回收并不会时刻进行,通常当V8认为时机合适时,才会进行触发垃圾回收。如周期性的触发,或可用内存很紧张时会特殊性调用。Node.js的每个进程的内存使用有限,所以V8必须谨慎使用。


教你如何在Node.js中发现JavaScript内存泄露

另一特殊性调用的情况,是造成性能急速下降的地方。

试想有一个app有诸多内存泄漏, 不久,Node进程会用尽内存,由此V8会触发特殊性内存回收。但自大多数数据依然可从根节点访问,只有非常少的数据会被清理。

不久,Node进程将再次用尽内存,触发另一次垃圾回收。在你察觉前,app会不断的进行垃圾回收,只是尝试让进程运行。尽管V8花了大多精力在垃圾回收,但只有非常少的资源留给实际的程序。

步骤 1、重现并确认问题

正如我前面所指出的,JavaScript的V8引擎使用了一套复杂的逻辑来觉id那个什么时候垃圾收集应该运行。明白了这个,就会知道尽管我们可以看到用于一个Node现成的内存在持续地增涨,我们还是不能确定自己是否目击了一次内存泄露, 直到我们知晓了垃圾收集已经运行起来,让不再被使用的内存可以被清理出来。

值得庆幸的是,Node允许我们手动触发垃圾回收,而这是在尝试确认一个内存泄露问题时我们应该要做的第一件事情。这件事情可以借助在运行Node 时带上 --expose-gc 标识(例如node --expose-gc index.js)来完成。一旦node以那个模式运行,你就可以用编程的方式通过从你的程序调用 global.gc() 来在任何时刻触发一次垃圾回收。

你也可以借助于调用 process.memoryUsage().heapUsed 来检测进程使用的内存数量。

通过手动触发垃圾回收并检测堆的使用情况,你就能够判别出自己是否实际地观察到了程序中的一次内存泄露。

示例程序

我已经创建了一个简单的内存泄露程序,你可以看看这儿: https://github.com/akras14/memory-leak-example

你可以把它clone下来,然后运行 node --expose-gc index.js 将它跑起来。

?

"usestrict" ;

require( 'heapdump' );

var leakyData=[]; var nonLeakyData=[];

class SimpleClass{

constructor(text){

this .text=text;

}

}

function cleanUpData(dataStore,randomObject){

var objectIndex=dataStore.indexOf(randomObject);

dataStore.splice(objectIndex,1);

}

function getAndStoreRandomData(){

var randomData=Math.random().toString();

var randomObject= new SimpleClass(randomData);

leakyData.push(randomObject);

nonLeakyData.push(randomObject);

//cleanUpData(leakyData,randomObject);//<--Forgottocleanup

cleanUpData(nonLeakyData,randomObject);

}

function generateHeapDumpAndStats(){

//1.Forcegarbagecollectioneverytimethisfunctioniscalled

try {

global.gc();

} catch (e){

console.log( "Youmustrunprogramwith'node--expose-gcindex.js'or'npmstart'" );

process.exit();

}

//2.OutputHeapstats

var heapUsed=process.memoryUsage().heapUsed;

console.log( "Programisusing" +heapUsed+ "bytesofHeap." )

//3.GetHeapdump

process.kill(process.pid, 'SIGUSR2' );

} //Kickofftheprogram

setInterval(getAndStoreRandomData,5); //Addrandomdataevery5milliseconds

setInterval(generateHeapDumpAndStats,2000); //Dogarbagecollectionandheapdumpevery2seconds

这个程序将会:

每过5毫秒生成一个随机的对象并将其存储到两个数组中,一个叫做 leakyData 而另外一个叫做 nonLeakyData 。每过5毫秒我们将清理掉 nonLeakyData 数组, 而我们将会“忘记”清理 leakyData 数组。

每过两秒程序就会输出内存的使用数量 (并发生堆的转储,而我们会在下一节对此进行更详细的描述)。

如果你使用 node --expose-gc index.js(或者是 npm start)来运行这个程序, 它就会开始输出内存的统计信息。我们让它跑一两分钟然后使用 Ctr + c 快捷键杀掉它(进程)。

你会看到内存使用在快速地上涨,尽管每两分钟我们都是触发了垃圾回收的,就在我们获得这份统计数据之前:

?

//1.Forcegarbagecollectioneverytimethisfunctioniscalled

try {

global.gc();

} catch (e){

console.log( "Youmustrunprogramwith'node--expose-gcindex.js'or'npmstart'" );

process.exit();

} //2.OutputHeapstats

var heapUsed=process.memoryUsage().heapUsed;

console.log( "Programisusing" +heapUsed+ "bytesofHeap." )

With the stats output looking something like the following:

本文前端(javascript)相关术语:javascript是什么意思 javascript下载 javascript权威指南 javascript基础教程 javascript 正则表达式 javascript设计模式 javascript高级程序设计 精通javascript javascript教程

主题: JavaJavaScriptNode.js数据定位变量过手
分页:12
转载请注明
本文标题:教你如何在Node.js中发现JavaScript内存泄露
本站链接:http://www.codesec.net/view/481363.html
分享请点击:


1.凡CodeSecTeam转载的文章,均出自其它媒体或其他官网介绍,目的在于传递更多的信息,并不代表本站赞同其观点和其真实性负责;
2.转载的文章仅代表原创作者观点,与本站无关。其原创性以及文中陈述文字和内容未经本站证实,本站对该文以及其中全部或者部分内容、文字的真实性、完整性、及时性,不作出任何保证或承若;
3.如本站转载稿涉及版权等问题,请作者及时联系本站,我们会及时处理。
登录后可拥有收藏文章、关注作者等权限...
技术大类 技术大类 | 前端(javascript) | 评论(0) | 阅读(35)