错误:CALL_AND_RETRY_LAST分配失败 - Javascript堆内存不足

时间:2017-06-12 16:00:28

标签: javascript memory memory-management memory-leaks

我目前正在学习Node JS和Javascript。我正在尝试开发一个应用程序来阅读和下载Mangas。

首先,我想建立一个数据库。这是我遇到问题的地方。 当我在我的服务器上运行我的程序有4GB的RAM(以填充我的数据库)我得到致命错误Javascript堆内存不足。

当我在本地计算机上使用8GB内存运行相同程序时,一切都按预期运行。

以下是我用Manga Chapters填充数据库的代码。

function insertChapters(callback){

    sql_selectAll("Mangas", function (selectError, selectResult) {
        if(!selectError){
            selectResult.forEach(function (mangaItem, mangaIndex) {
                gin.mangafox.chapters(mangaItem.Title)
                    .then(chapters =>{

                        chapters.forEach(function (chapterItem) {
                            var Chapter = {
                                Title: chapterItem.name,
                                NR: chapterItem.chap_number,
                                URL: chapterItem.src,
                                MangaID: mangaItem.MangaID,
                                MangaName: mangaItem.Title,
                                VolumeNR: chapterItem.volume
                            };
                            sql_insertInto("Chapters", Chapter, function (insertError, insertResult) {
                            if(!insertError){
                                var insertedChapter =
                                "------------------------------------------------------------------------\n" +
                                "  Added new Chapter: " + Chapter.NR + " For: " + mangaItem.Title + "\n" +
                                "------------------------------------------------------------------------\n";
                                callback(null,insertedChapter ,insertResult);
                            }
                            else{
                                if(insertError.code === "ER_DUP_ENTRY") {
                                    var dupEntry = "------------------------------------------------------------------------\n" +
                                                   "  Duplicate Entry: Chapter: " + Chapter.NR + " For: " + mangaItem.Title + "\n" +
                                                   "------------------------------------------------------------------------\n"

                                        callback(null, dupEntry, null);
                                    }
                                    else{
                                        callback(insertError, null, null);
                                    }
                                }
                            })
                        })

                    })
                    .catch(fetchChapterError => {
                        callback(fetchChapterError, null, null);
                    })
            })
        }
        else{
            callback(selectError, null, null);
        }
    });
}`

我真的不知道如何解决这个问题,因为我不确定问题是什么:

  1. 问题只是我的服务器中没有足够的RAM吗?
  2. 我的代码有问题吗?我在某个地方泄漏了记忆吗?
  3. 我的代码可能需要那么多内存吗?
  4. 非常感谢你,我感谢你能得到的每一个帮助。

    编辑:

    function sql_selectAll(tableName, callback){
        var sql = 'SELECT * FROM `' + tableName + '`';
        connection.query(sql, function (err, selectAllResult) {
            callback(err, selectAllResult);
        })
    }
    
    function sql_insertInto(tableName, insertionObject, callback) {
        var sql = 'insert into ' + tableName + ' set ?';
        connection.query(sql, insertionObject, function (err, insertResult) {
            callback(err, insertResult);
        });
    }
    

1 个答案:

答案 0 :(得分:0)

您正在同时为每个SQL结果调用mangafox端点,而不是一次调用一个或以块为单位。您可以尝试使用async/await。我不熟悉您正在使用的sql API,但假设方法sql_selectAllsql_insertInto返回promises如果没有给出回调,您可以将函数重写为像这样的东西:

async function insertChapters(callback) {
    try {
        const mangas = await sql_selectAll("Mangas");
        for (const mangaItem of mangas) {
            const chapters = await gin.mangafox.chapters(mangaItem.Title);
            for (const chapterItem of chapters) {
                const Chapter = {
                    Title: chapterItem.name,
                    NR: chapterItem.chap_number,
                    URL: chapterItem.src,
                    MangaID: mangaItem.MangaID,
                    MangaName: mangaItem.Title,
                    VolumeNR: chapterItem.volume
                };
                try {
                    const insertResult = await sql_insertInto("Chapters", Chapter);
                    const insertedChapter =
                    "------------------------------------------------------------------------\n" +
                    "  Added new Chapter: " + Chapter.NR + " For: " + mangaItem.Title + "\n" +
                    "------------------------------------------------------------------------\n";
                    callback(null, insertedChapter, insertResult);
                } catch (error) {
                    if (error.code === "ER_DUP_ENTRY") {
                        const dupEntry = "------------------------------------------------------------------------\n" +
                                       "  Duplicate Entry: Chapter: " + Chapter.NR + " For: " + mangaItem.Title + "\n" +
                                       "------------------------------------------------------------------------\n";
                        callback(null, dupEntry, null);
                    } else {
                        throw error;
                    }
                }
            }
        }
    } catch (error) {
        callback(error, null, null);
    }
}

注意await个关键字 - 这些关键字在async function中是允许的,并且基本上告诉JS引擎暂停异步函数的执行,并在等待的承诺结算之前执行其他操作。

另请注意,在使用try关键字处理承诺时,您可以使用常规的旧式catch / await块!我没有做任何特殊处理fetchChapterError的事情,因为它将由最外面的catch块处理!此外,对于插入错误,如果它不是重复条目,我们可以重新抛出错误,并让它也被最外面的catch块捕获。

如果你的SQL函数没有返回promises,那么在Node version 8(最新版本)上你可以使用util.promisify

const util = require('util');
sql_selectAll = util.promisify(sql_selectAll);

如果你没有使用Node 8,那么你可以使用另一个promisify实现(例如,查看bluebird),或者你可以很容易地编写自己的(阅读关于promises的MDN文章) )。