递归 - 节点内存不足
Recursion - Node out of memory
当我运行以下代码9999999+次时,Node返回:
FATAL ERROR: CALL_AND_RETRY_2 Allocation failed - process out of memory
Aborted (core dumped)
除了增加最大分配大小或任何命令行参数之外,解决此问题的最佳解决方案是什么?
我想提高代码质量,而不是破解解决方案。
以下是应用程序中的主要递归。
该应用程序是一个负载测试工具。
a.prototype.createClients = function(){
for(var i = 0; i < 999999999; i++){
this.recursiveRequest();
}
}
a.prototype.recursiveRequest = function(){
var self = this;
self.hrtime = process.hrtime();
if(!this.halt){
self.reqMade++;
this.http.get(this.options, function(resp){
resp.on('data', function(){})
.on("connection", function(){
})
.on("end", function(){
self.onSuccess();
});
})
.on("error", function(e){
self.onError();
});
}
}
a.prototype.onSuccess = function(){
var elapsed = process.hrtime(this.hrtime),
ms = elapsed[0] * 1000000 + elapsed[1] / 1000
this.times.push(ms);
this.successful++;
this.recursiveRequest();
}
看起来你真的应该使用队列而不是递归调用。 async.queue
为处理异步队列提供了一种出色的机制。 您还应考虑使用 request
模块来简化 http 客户端连接。
var async = require('async');
var request = require('request');
var load_test_url = 'http://www.testdomain.com/';
var parallel_requests = 1000;
function requestOne(task, callback) {
request.get(task.url, function(err, connection, body) {
if(err) return callback(err);
q.push({url:load_test_url});
callback();
});
}
var q = async.queue(requestOne, parallel_requests);
for(var i = 0; i < parallel_requests; i++){
q.push({url:load_test_url});
}
您可以根据要同时访问测试服务器的请求数来设置 parallel_requests
变量。
您正在并行启动 10 亿个"客户端",并让每个客户端以无休止的递归方式递归地执行 http get 请求。
几点评论:
- 当您的问题提到 1000 万个客户端时,您的代码创建了 10 亿个客户端。
- 您应该将
for
循环替换为递归函数,以消除内存不足错误。
这些行中的内容:
a.prototype.createClients = function(i){
if (i < 999999999) {
this.recursiveRequest();
this.createClients(i+1);
}
}
- 然后,您可能希望在客户端创建之间或对
recursiveRequest
的调用之间包括一些延迟。使用setTimeout
. - 你应该有办法让递归停止(
onSuccess
和recursiveRequest
继续互相调用) - 像异步节点.js模块这样的流控制库可能会有所帮助。
>1000万是非常大的...假设堆栈支持任意数量的调用,它应该可以工作,但你可能会要求 JavaScript 解释器加载 1000 万 x 相当多的内存......结果是内存不足。
此外,我个人不明白为什么您希望同时拥有如此多的请求(在服务器上测试负载过重?)一种优化方法是不要创建您正在做很多的"浮动函数"。"浮动函数"在每个实例化上使用自己的一组内存。
this.http.get(this.options, function(resp){ ... });
^^^^
++++--- allocates memory x 10 million
在这里,function(resp)...
声明在每个调用上分配更多内存。您要做的是:
# either global scope:
function r(resp) {...}
this.http.get(this.options, r ...);
# or as a static member:
a.r = function(resp) {...};
this.http.get(this.options, a.r ...);
至少你会节省所有的函数内存。当然,这适用于您在 r 函数中声明的所有函数。特别是如果有相当大的。
如果你想使用 this 指针(使r
成为一个原型函数),那么你可以这样做:
a.prototype.r = function(resp) {...};
// note that we have to have a small function to use 'that'... probably not a good idea
var that = this;
this.http.get(this.options, function(){that.r();});
为避免that
引用,您可以使用保存在全局中的实例。不过,这破坏了对象的使用:
a.instance = new a;
// r() is static, but can access the object as follow:
a.r = function(resp) { a.instance.<func>(); }
使用该实例,您可以从静态r
函数访问对象的函数。这可能是实际的实现,可以充分利用this
参考:
a.r = function(resp) { a.instance.r_impl(); }
根据 Daniel 的评论,您的问题是您滥用for()
来计算要发送的请求总数。这意味着您可以对代码应用非常简单的修复,如下所示:
a.prototype.createClients = function(){
this.recursiveRequest();
};
a.prototype.recursiveRequest = function(){
var self = this;
self.hrtime = process.hrtime();
if(!this.halt && this.successful < 10000000){
...
您的递归性足以运行测试任意次数。
不过,你所做的是永不放弃。您有一个halt
变量,但看起来您从未将其设置为 true。但是,要测试 1000 万次,您需要检查已发送的请求数。
我的"修复"假设onError()失败(没有递归)。您还可以更改代码以使用 halt 标志,如下所示:
a.prototype.onSuccess = function(){
var elapsed = process.hrtime(this.hrtime),
ms = elapsed[0] * 1000000 + elapsed[1] / 1000
this.times.push(ms);
this.successful++;
if(this.successful >= 10000000)
{
this.halt = true;
}
this.recursiveRequest();
}
请注意,您将在时间缓冲区中推送 ms 1000 万次。那是一张大桌子!您可能希望有一个总计,并在最后计算一个平均值:
this.time += ms;
// at the end:
this.average_time = this.time / this.successful;
- node.js上的过程性2d数组mongoDB插入内存不足
- 从redis到elasticsearch的Node.js脚本副本内存不足
- WebStorm运行非常非常慢,并且不断出现内存不足的错误
- nodejs在处理csv文件时内存不足
- Web工作程序在处理大型数组时内存不足
- 移动野生动物园崩溃日志 - 内存不足
- 我的 JavaScript 暴力递归数独求解器内存不足吗?
- 小程序在 OSX 上的 Node 中内存不足
- Dojo 1.7 构建:内存不足错误
- File Uploads & Chrome (BROWSER) 内存不足
- 由于数组大小,Javascript 主要浏览器的内存不足
- 在 Emscripten'd C++ 程序中处理数据后,如何修复尝试从 Web worker 发回数据时的“内存不足”错
- Node JavaScript 递归内存不足
- IE(any)和Firefox中的内存不足错误,当尝试从父文档包含jQuery时
- 递归 - 节点内存不足
- 想要使用 html5 的画布优化捕获的图像调整大小和旋转的代码,现在在移动设备上发出内存不足警告
- 通过webpack绑定时,获取GC,进程内存不足错误
- 闭包编译器(ccjs)内存不足错误
- 如何使用log4j或winston编写大量日志?内存不足
- 得到“;未捕获的异常:内存不足”;在firebug中执行ajax调用