【问题标题】:Event Emitter Memory Leak in Electron AppElectron App 中的事件发射器内存泄漏
【发布时间】:2020-10-14 06:43:30
【问题描述】:

我正在开发一个 React Electron 应用程序,我的应用程序的多个区域都存在事件发射器内存泄漏问题。我对 Node.js 不是很有经验,所以请原谅我的业余错误。

(node:3142) MaxListenersExceededWarning: Possible EventEmitter memory leak detected. 11 file:minified listeners added to [EventEmitter]. Use emitter.setMaxListeners() to increase limit

请注意,从长远来看,这给我的应用程序带来了问题,所以这不是我会简单地“解决”或使用setMaxListeners() 保持沉默的问题。

基本上,用户会删除一些文件,然后开始一个链。我创建了一个事件进程,将缩小的文件添加到渲染器进程的列表中:

  1. 对于每个删除的文件,将文件发送到主进程进行修改。

    App.js(渲染过程):
document.ondrop = (e) => {
        e.preventDefault();
        e.stopPropagation();
        handleFiles(e.dataTransfer.files);
    };

const sendFiles = (files) => {
        for (let file of files) {
            file = file.path || file;

            // if file is a folder, recursively check each file in the nested folders
            if (fs.lstatSync(file).isDirectory()) {
                // rename for clarity
                let folder = file;
                let files = fs.readdirSync(folder).map((fileName) => {
                    return path.join(folder, fileName);
                });
                sendFiles(files);
            } else {
                // don't add duplicate files to list
                if (list.some((item) => item.oPath === file.path)) {
                    return false;
                }
                ipcRenderer.send("file:add", file);
            }
        }
    };
  1. 缩小每个单独的文件并将缩小后的路径发送回渲染器进程以进行显示。

    main.js(主进程):
ipcMain.on("file:add", (e, path) => {
        minifyFile(path, mainWindow);
    });

const minifyFile = (filePath, mainWindow) => {
...
        mainWindow.webContents.send(
            "file:minified",
            {
                path: saveLocation,
                name: name,
                type: extension,
                oSize: originalSize,
                nSize: newSize,
                oPath: filePath,
                newName: newName,
            }
        );
...
}
  1. 现在我们有了要显示的每个缩小文件的文件信息,请将其添加到 React 中的列表状态。

    App.js(再次渲染进程):
ipcRenderer.on("file:minified", (e, data) => {
        // if item's path already exists on list, don't add it
        if (list.some((item) => item.path === data.path)) {
            return false;
        } else {
            let newList = list;
            newList.push({
                name: data.name,
                path: data.path,
                type: data.type,
                oSize: data.oSize,
                nSize: data.nSize,
                oPath: data.oPath,
                newName: data.newName,
            });

            setList(newList);
            console.log(list);
        }
});

发生这种情况时,文件会按预期添加,但随着我在程序的整个生命周期中继续删除更多文件,调用“file:minified”的事件发射器会呈指数增长,这开始在我的程序的其他部分给我带来问题,因为现在它尝试将项目添加到列表中近数百次。

如果有人能帮助我找出我所犯的错误,我将不胜感激,因为我对 Node.js 中的这些问题有点盲目。

这是我需要删除事件侦听器的东西吗?正如我所说,我对这些都不太确定。

我的应用程序的渲染器进程中也出现了另一个内存泄漏问题,任何人有兴趣检查一下是否可以链接它们;我完全不知道。 Here's my other thread.

【问题讨论】:

标签: node.js reactjs memory-leaks electron eventemitter


【解决方案1】:

看起来您每次发送都收到来自主进程的单个响应。如果是这种情况,您可以使用 ipcRenderer.invoke()ipcMain.handle() 之类的...

App.js

document.ondrop = (e) => {
        e.preventDefault();
        e.stopPropagation();
        handleFiles(e.dataTransfer.files);
    };

const sendFiles = (files) => {
        for (let file of files) {
            file = file.path || file;

            // if file is a folder, recursively check each file in the nested folders
            if (fs.lstatSync(file).isDirectory()) {
                // rename for clarity
                let folder = file;
                let files = fs.readdirSync(folder).map((fileName) => {
                    return path.join(folder, fileName);
                });
                sendFiles(files);
            } else {
                // don't add duplicate files to list
                if (list.some((item) => item.oPath === file.path)) {
                    return false;
                }
                ipcRenderer.invoke("file:add", file)
                    .then((data) => handleMinified(data)})
            }
        }
    };

const handleMinified = (data) => {
    // if item's path already exists on list, don't add it
    if (list.some((item) => item.path === data.path)) {
        return false;
        } 
    else {
        let newList = list;
        newList.push({
            name: data.name,
            path: data.path,
            type: data.type,
            oSize: data.oSize,
            nSize: data.nSize,
            oPath: data.oPath,
            newName: data.newName,
            });

            setList(newList);
            console.log(list);
        }

    };

main.js

ipcMain.handle("file:add", (e, path) => {
        const data = await minifyFile(path);
        return data;
    });


const minifyFile = (filePath, mainWindow) => {
    ...
            return {
                path: saveLocation,
                name: name,
                type: extension,
                oSize: originalSize,
                nSize: newSize,
                oPath: filePath,
                newName: newName,
            }
}

这样,事件侦听器会为您移除 :)

https://www.electronjs.org/docs/api/ipc-renderer#ipcrendererinvokechannel-args

【讨论】:

    猜你喜欢
    • 2013-11-05
    • 1970-01-01
    • 2017-01-29
    • 2011-06-27
    • 1970-01-01
    • 2018-05-03
    • 2021-08-29
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多