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

问题描述 投票:0回答:1

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

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

当我在我的本地计算机上使用8GB RAM运行相同的程序时,一切正常。

这是我用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. 我的代码可能需要那么多内存吗?

非常感谢你,我很感激我能得到的每一个帮助。

编辑:

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);
    });
}
javascript memory memory-management memory-leaks
1个回答
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 functions中是允许的,并且基本上告诉JS引擎暂停执行异步函数并执行其他操作,直到等待的promise得到解决。

另请注意,使用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文章)。

© www.soinside.com 2019 - 2024. All rights reserved.