Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

EventEmitter in JavaScript can cause out of memory #302

Open
RajaaAbdallah opened this issue Jun 19, 2023 · 0 comments
Open

EventEmitter in JavaScript can cause out of memory #302

RajaaAbdallah opened this issue Jun 19, 2023 · 0 comments

Comments

@RajaaAbdallah
Copy link

RajaaAbdallah commented Jun 19, 2023

How can I avoid memory leaks caused by event listeners and event emissions in my Electron app, specifically when continuously reading data from a connected device through a serial port?

I have developed a desktop app using Electron.js and TypeScript. The purpose of this app is to read real-time data from a device connected to it. The app needs to continuously read both analog and digital data from the device. Initially, when the device is connected and data reading is started by listening to the serial port session, everything works fine. However, after approximately 2 hours of continuous data reading from the serial port session, an error occurs:

[electron] <--- Last few GCs --->
[electron]
[electron] [11247:0x3aa8002c0000] 4812376 ms: Scavenge 10.4 (20.9) -> 4.2 (20.9) MB, 0.13 / 0.00 ms (average mu = 1.000, current mu = 1.000) task;
[electron] [11247:0x3aa8002c0000] 4812823 ms: Scavenge 10.4 (20.9) -> 4.2 (20.9) MB, 0.13 / 0.00 ms (average mu = 1.000, current mu = 1.000) task;
[electron] [11247:0x3aa8002c0000] 4813281 ms: Scavenge 10.4 (20.9) -> 4.2 (20.9) MB, 0.19 / 0.00 ms (average mu = 1.000, current mu = 1.000) task;
[electron]
[electron]
[electron] <--- JS stacktrace --->
[electron]
[electron] FATAL ERROR: Cannot grow ExternalPointerTable past its maximum capacity Allocation failed - process out of memory

To provide you with more information, here is the code I have written:

First, the open() method is responsible for opening the serial port connected to the device:
`open(): Promise {
return new Promise(async (resolve, reject) => {
const port = new SerialPort(
{
path: this.sessionInfo.path,
baudRate: this.sessionInfo.buadRate,
dataBits: 8,
stopBits: 2,
parity: "none",
},

    function (err) {
      if (err) {
        reject(err);
      }
    }
  );
  this.dataReaderParser = this.sessionInfo.readLineParser;

  port.pipe(this.bufferCleanerParser);
  this.bufferCleanerParser.on("data", (data: Buffer) => {
    console.log(`Cleared data: ${data.toString("hex")}`);
  });
  await new Promise<void>((resolve) => {
    setTimeout(() => {
      port.unpipe(this.bufferCleanerParser);
      port.pipe(this.dataReaderParser);
      resolve();
    }, 10);
  });

  const onData = (data: string) => {
    if (this.onDataCallback) {
      this.onDataCallback(data);
    }
    this.emit('data', data);
  };

  this.dataReaderParser.on('data', onData);

  this.port = port;
  resolve();
});

}
Next, the read() method is used to listen for emitted data:public read(
callback: (data: string) => void,
sendFlag?: boolean
): Promise {
if (callback) {
return new Promise((resolve, reject) => {
if (sendFlag) {
this.onDataCallback = (data: string) => {
callback(data);
};

      return;

    }

    this.on("data", (data) => {
      callback(data);
    });
  });
}
return Promise.resolve("the callback is not provided");

} Finally, the readAnalog() method is called when the start button is pressed on the UI to continuously read data from the connected device:async readAnalog(decoder: DecoderInterface, callback: (data: PowerDeliveryAnalogModel|any) => void) {
try {
this.writeDigital()
const session = this.sessionManager.getSession("serialPortSession2");

  session.read(async (data: string) => {
    try {
      this.counter++;
      if (this.counter === 50) {
        const parserAnalogData = this.parser.parseAnalogData(data);
        const res: PowerDeliveryAnalogModel =
          decoder.decodeAnalogData(parserAnalogData);
        callback(res);
        this.counter = 0;
      }
    } catch (error) {}
  });
} catch (error) {}

}
`

After initiating the app to continuously read analog data from the device, it functions smoothly for approximately 2 hours. However, after this period, the app crashes due to insufficient memory, resulting in the exception shown in the following image: Image description
so how we can avoid memory leak that occur by event listener and emit the event as i guess in my case?

@RajaaAbdallah RajaaAbdallah changed the title eventemitter cause memory leak after 2 hours from now EventEmitter in JavaScript can cause out of memory Jun 19, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant