node+mongoose.save out of memory

来源:互联网 发布:彩票双色球大赢家软件 编辑:程序博客网 时间:2024/06/07 03:16

在mongoose存入过程中node报出out of memory,由于之前数据量小的时候并没有这个错误,本次运行只是增加了数据量,因此将错误定位在存储的过程。
查了许久也没找到现成的方案让我ctrl+c,node新手+mongoose新手,只能靠自己猜、、幸好折腾了一天,才算有个解决方案。
一个小例子还原现场:

var mongoose = require('mongoose');mongoose.connect('mongodb://localhost/test', {useMongoClient: true});mongoose.Promise = global.Promise;mongoose.set("debug", true);var Cat = mongoose.model('Cat', {    name: {type:String},    prop1: {type:String},    prop2: {type:String},    prop3: {type:String},    prop4: {type:String},    prop5: {type:String},    prop6: {type:String},    prop7: {type:String},    prop8: {type:String},    prop9: {type:String}});Cat.remove({}, function (err) {    if (err) {        console.log(err);    } else {        console.log("清空Cat");    }});for (var i = 0; i < 100000; i++) {    var kitty = new Cat({        name: 'Zildjian',        prop1: "prop1 of cat " + i,        prop2: "prop2 of cat " + i,        prop3: "prop3 of cat " + i,        prop4: "prop4 of cat " + i,        prop5: "prop5 of cat " + i,        prop6: "prop5 of cat " + i,        prop7: "prop5 of cat " + i,        prop8: "prop5 of cat " + i,        prop9: "prop5 of cat " + i    });    kitty.save((function(index){        return function (err) {        if (err) {            console.log(err);        } else {            console.log('meow cat '+index);        }    }})(i));

为了让它迅速oom,设置了最大老生代空间为900,运行:
node --max-old-space-size=900 ./bin/www
得到报错:

<--- Last few GCs --->   72238 ms: Mark-sweep 817.6 (903.8) -> 817.5 (904.8) MB, 621.4 / 0.0 ms [allocation failure] [GC in old space requested].   72867 ms: Mark-sweep 817.5 (904.8) -> 817.6 (906.8) MB, 629.2 / 0.0 ms [allocation failure] [GC in old space requested].   73521 ms: Mark-sweep 817.6 (906.8) -> 823.0 (903.8) MB, 653.2 / 0.0 ms [lastresort gc].   74167 ms: Mark-sweep 823.0 (903.8) -> 828.4 (903.8) MB, 646.2 / 0.0 ms [lastresort gc].<--- JS stacktrace --->==== JS stack trace =========================================Security context: 000002B9F4A3FA99 <JS Object>    2: write [D:\server\monitor\node_modules\mongodb-core\lib\connection\pool.js:984] [pc=0000022F20E09E62] (this=000001985C65C779 <a Pool with map 000000B3AF5B8DF9>,commands=000001F7DDC54471 <a Query with map 000000B3AF5B6F61>,options=000000645A4B4579 <an Object with map 000000B3AF584109>,cb=0000021F10211521 <JS Function resultHandler (SharedFunctionInfo 0000016FCCA4FAA9)>)    3: executeWri...FATAL ERROR: CALL_AND_RETRY_LAST Allocation failed - JavaScript heap out of memory

分析过程:
将原代码存入的数据量调为10只,看一下打印的结果:
老代码输出

鱼唇的我想了好久才想到可能是这样的(ps:以下过程全靠猜的,不一定对)
model.save(fn) 这个方法是异步的,它被调用结束才开始调用它的回调函数。
for循环中将save添加到待运行的队列,每执行一个save又将它的回调添加到队尾,因此,在所有save完成之前不会执行任何一个save的回调函数。
从输出的结果来看,也是将所有save运行完之后,再运行所有的回调函数。
而回调函数维护了自己的数据,这里,并不知道它维护了哪些,可能是比较大的。
在报出oom的时候,上一条输出依然还是mongoose的insert数据的记录,此时已经运行过的save函数,都添加了一个回调等待运行,可能是这些回调函数维护的数据占据了大量内存。
因此,想到一条存完之后,立刻执行它的回调函数,这样使回调函数维护的数据得以释放。

最终解决方案:一只一只存

var mongoose = require('mongoose');mongoose.connect('mongodb://localhost/test', {useMongoClient: true});mongoose.Promise = global.Promise;mongoose.set("debug", true);var Cat = mongoose.model('Cat', {    name: {type:String},    prop1: {type:String},    prop2: {type:String},    prop3: {type:String},    prop4: {type:String},    prop5: {type:String},    prop6: {type:String},    prop7: {type:String},    prop8: {type:String},    prop9: {type:String}});Cat.remove({}, function (err) {    if (err) {        console.log(err);    } else {        console.log("清空Cat");    }});saveNextCat(0);function saveNextCat(i){    if(i<10000){        var kitty = new Cat({            name: 'Zildjian',            prop1: "prop1 of cat " + i,            prop2: "prop2 of cat " + i,            prop3: "prop3 of cat " + i,            prop4: "prop4 of cat " + i,            prop5: "prop5 of cat " + i,            prop6: "prop5 of cat " + i,            prop7: "prop5 of cat " + i,            prop8: "prop5 of cat " + i,            prop9: "prop5 of cat " + i        });        kitty.save((function(index){            return function (err) {                if (err) {                    console.log(err);                } else {                    console.log('meow cat '+index);                }                i++;                saveNextCat(i);            }})(i));    }else{        return;    }}

更改过后的程序的输出为:
新代码输出

可以看到,存完之后立刻执行了回调函数,并在相同的最大老生代空间下使所有数据都存储完成。

原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 橡胶底的劳保鞋开胶了怎么办? 求部队停止有偿服务内部超市怎么办 晋江买了全本还是有防盗章节怎么办 宝宝没有穿衣服的地方长疙瘩怎么办 詹姆斯士兵12魔术贴老是掉怎么办 手机版本不支持陌陌视频聊天怎么办 私人单位不给员工写收入证明怎么办 cad图形缩小后找不到图了怎么办 离婚了老婆嫁给了别人怎么办 对方开车撞伤人逃逸不赔钱怎么办 帮老板开车撞伤人老板不愿赔怎么办 我开车撞人现在伤者住院怎么办 B照驾驶证扣3分怎么办l 驾驶证被盗后被别人拿去消分怎么办 碰瓷的手碰我后视镜怎么办 摩托被盗监控录像器没有记录怎么办 车贷逾期车被贷款公司拖走了怎么办 发现邻居家小孩偷了我的钱该怎么办 孕晚期挺着大肚子好累怎么办 古墓丽影崛起东西满了怎么办 塞尔达传说大师剑耐久没了怎么办 冒险岛遇见超能力者全屏挂机怎么办 当危险来临时该怎么办作文400字 生气把孩子手掌内侧打肿了怎么办 驾驶证未满一年扣12分怎么办 在高速上超速百分之10以下怎么办 中兴手机重启死机开不了机怎么办 太胖了太自卑了该怎么办 儿子因为长的胖特别自卑怎么办? 苹果ld叫我检查身份信息怎么办 我家墙让对面给漂水了怎么办 如果你流落到荒岛上你会怎么办 手机迅雷下载版权方不给下载怎么办 白色有彩色花纹的衣服染色了怎么办 载兰花假如下雪和打霜怎么办 皇室战争你的队友离开了对战怎么办 海岛奇兵发现求救信号第三个怎么办 海岛奇兵勋章太多对手太强怎么办 鱼为什么换缸鱼翅黑了怎么办 鱼丸捕鱼大作战换手机了怎么办 2o岁j'j小怎么办