1

I am attempting to write a function that waits for a promise to execute, executes the promise, and then start to wait for the promise to execute again.

I have tried a few looping examples, but all seem to have caused memory leaks.

This is a mock for a library that I am using.

const waitForMessage = (topics, cb) => {
    setTimeout(() => {
        cb(null, query, "test/request")
    }, 250);
}

Which I converted to a standard es6 Promise.

const waitForRequest = () =>
    new Promise((res, rej) =>
        waitForMessage([], (err, query, topic) =>
            err ? rej(query, topic) : res(query, topic)));

And this seems to work fine....

The Problem seems to be when I try iterating over this infinitely...

Conceptually, I would like to do something like this (which has documented issues in the specification)

// Warning: JS implementation will leak memory!!!
const loop = () =>
    waitForRequest()
        .then(() => loop());

loop();

However, I have found that even a synchronous loop seems to produce a simular memory leak here...

const handleEvent = () =>
    waitForRequest()
        .then((query, topic) => graphql(schema, query))
        .then((data) => {
            console.log(`graphql -> recieved data: ${JSON.stringify(data)}`)
        })
        .catch((err) => {
            console.log(`ERROR: ${err}`)
        });

const run = async () => {
    while (true) {
        await handleEvent()
    }
}

run();

I sampled the heap profile and found the top down call stack to be...

- [14.5%] emitHook
- [0%] (anon)
  - [0%] handleEvent
    - [0%] then
      - [0%] emitInitNative
        - [69.45%] add    <- where the majority of the heap is being allocated.
    - [0%] waitForRequest
      - [0%] Promise
        - [0%] (anon)
          - [0%] waitForMessage
            - [0%] setTimeout
              - [16%] insert

Which seems to imply that the .then() and ultimately the .add() call is consuming about 70% of the heap (and growing...). As I sample the heap, it seems as it is growing at a rate of 1-7 kB/s.

How can squash this memory leak? Or is there a better design pattern to use for this type of situation? Any help is appreciated, still relatively new to using javascript.

  • Did the garbage collector run inbetween? – Jonas Wilms Apr 17 '21 at 15:28
  • I believe so... I was monitoring the heap over a good amount of time (so I assume it should have run). However, I do not have any code that interacts with the gc. – тнσмαѕ ѕтєιинσℓz Apr 17 '21 at 15:44
  • With the Chrome developer tools you can trigger a gc cycle. If you are unsure wether a gc cycle happened, you actually don't even know wether you are leaking memory. – Jonas Wilms Apr 17 '21 at 16:12
  • I am using the node remote debugging with chrome tools (chrome://inspect) to log the heap - I don't actually see the option to trigger it, I have just been profiling the heap over time (and looking at the node process and how much it is allocating in top) – тнσмαѕ ѕтєιинσℓz Apr 17 '21 at 16:35
  • https://stackoverflow.com/questions/27321997/how-to-request-the-garbage-collector-in-node-js-to-run – Jonas Wilms Apr 17 '21 at 16:44

0 Answers0