Проблема с памятью JSZip

Я испытываю большое потребление памяти в своем приложении Node.js, когда загружаю zip-файлы размером ~ 100 МБ один за другим, он сохраняет их в памяти как «NodeBufferReader». Библиотека, которую я использую, называется JSZip и находится здесь: https://stuk.github.io/jszip/

Если я обращаюсь к одному и тому же zip-файлу дважды, это не увеличивает использование памяти, но для каждого «дополнительного» .zip-файла, к которому я обращаюсь, память увеличивается примерно на размер .zip-файла. Файлы, к которым я обращаюсь, имеют размер около 100 МБ или больше, поэтому, как вы можете себе представить, они могут стать довольно большими и довольно быстро.

Приложение Node.js — это сервер веб-сокетов, который считывает файлы из ZIP-файлов и возвращает их запрашивающей стороне в виде данных base64. Рассматриваемая функция находится здесь:

function handleFileRequest(args, connection_id) {
    var zipIndex = 0,
        pathLen = 0,
        zip_file = "",
        zip_subdir = "";
    try {
        if (args.custom.file.indexOf(".zip") > -1) {
            // We have a .zip directory!
            zipIndex = args.custom.file.indexOf(".zip") + 4;
            pathLen = args.custom.file.length;

            zip_file = args.custom.file.substring(0, zipIndex);
            zip_subdir = args.custom.file.substring(zipIndex + 1, pathLen);

            fs.readFile(zip_file, function (err, data) {
                if (!err) {
                    zipObj.load(data);
                    if (zipObj.file(zip_subdir)) {
                        var binary = zipObj.file(zip_subdir).asBinary();
                        var base64data = btoa(binary);
                        var extension = args.custom.file.split('.').pop();
                        var b64Header = "data:" + MIME[extension] + ";base64,";
                        var tag2 = args.custom.tag2 || "unset";
                        var tag3 = args.custom.tag3 || "unset";

                        var rargs = {
                            action: "getFile",
                            tag: args.tag,
                            dialogName: connections[connection_id].dialogName,
                            custom: {
                                file: b64Header + base64data,
                                tag2: tag2,
                                tag3: tag3
                            }
                        };
                        connections[connection_id].sendUTF(JSON.stringify(rargs));

                        rargs = null;
                        binary = null;
                        base64data = null;
                    } else {
                        serverLog(connection_id, "Requested file doesn't exist");
                    }
                } else {
                    serverLog(connection_id, "There was an error retrieving the zip file data");
                }
            });

        } else {
            // File isn't a .zip
        }
    } catch (e) {
        serverLog(connection_id, e);
    }
}

проблема с памятью

Любая помощь будет высоко оценена в избавлении от этой проблемы - Спасибо!

Пример рабочего кода

function handleFileRequest(args, connection_id) {
    var zipIndex = 0,
        pathLen = 0,
        f = "",
        d = "";
    try {
        if (args.custom.file.indexOf(".zip") > -1) {
            // We have a .zip directory!
            zipIndex = args.custom.file.indexOf(".zip") + 4;
            pathLen = args.custom.file.length;

            f = args.custom.file.substring(0, zipIndex);
            d = args.custom.file.substring(zipIndex + 1, pathLen);

            fs.readFile(f, function (err, data) {
                var rargs = null,
                    binary = null,
                    base64data = null,
                    zipObj = null;

                if (!err) {

                    zipObj = new JSZip();
                    zipObj.load(data);

                    if (zipObj.file(d)) {
                        binary = zipObj.file(d).asBinary();
                        base64data = btoa(binary);
                        var extension = args.custom.file.split('.').pop();
                        var b64Header = "data:" + MIME[extension] + ";base64,";
                        var tag2 = args.custom.tag2 || "unset";
                        var tag3 = args.custom.tag3 || "unset";

                        rargs = {
                            action: "getFile",
                            tag: args.tag,
                            dialogName: connections[connection_id].dialogName,
                            custom: {
                                file: b64Header + base64data,
                                tag2: tag2,
                                tag3: tag3
                            }
                        };
                        connections[connection_id].sendUTF(JSON.stringify(rargs));
                    } else {
                        serverLog(connection_id, "Requested file doesn't exist");
                    }
                } else {
                    serverLog(connection_id, "There was an error retrieving the zip file data");
                }

                rargs = null;
                binary = null;
                base64data = null;
                zipObj = null;
            });

        } else {
            // Non-Zip file
        }
    } catch (e) {
        serverLog(connection_id, e);
    }
}

person trvo    schedule 29.12.2014    source источник


Ответы (1)


Если вы используете один и тот же экземпляр JSZip для загрузки каждого файла, вы будете хранить все в памяти: метод load не заменяет существующее содержимое.

Попробуйте каждый раз использовать новый экземпляр JSZip:

var zipObj = new JSZip();
zipObj.load(data);
// or var zipObj = new JSZip(data);
person David Duponchel    schedule 29.12.2014
comment
Сначала я попробовал это, но в итоге получил более 2 ГБ использования памяти после нескольких запросов одних и тех же данных, поэтому был вынужден использовать .load(), это фактически сломало node-webkit, даже установка zipObj на ноль не освободила памяти с помощью этого метода. - person trvo; 30.12.2014
comment
Не знаю, что я делал, когда пробовал это в первый раз, но я перетасовал часть кода и снова использовал этот метод, теперь размер кучи 8,6 МБ, гораздо более практичный, спасибо! - person trvo; 30.12.2014