Dandan
Dandan

Reputation: 529

Understanding Chrome GC with async methods

I'm trying to figure out whether a memory leak can be created by an async function that never resumes. For example:

  function timeout(ms) {
    return new Promise(resolve => setTimeout(resolve, ms));
  }

  function Test() {
    this.arr = [];

    this.alloc = async function() {
      for (i = 0; i < 300000; i++) {
        this.arr.push(document.createElement('div'));
      }
      await timeout(10000);
      alert('done waiting ' + this.arr.length); // outputs 300000
    };
  };

  var test = new Test();

  function leak() {
    test.alloc();
    test = null;
    window.gc(); // Running chrome with expose-gc flag
    // Snapshotting memory here shows divs have been deallocated
  }

Using Chrome's memory tools, I grabbed a snapshot when this code finishes executing. I would have expected to see 300000 HTMLDivElements still allocated, but lo and behold - the memory seems "freed". What's strange is if I try to access the array contents they are still there. Can anyone explain this phenomenon?

Upvotes: 2

Views: 438

Answers (1)

Bergi
Bergi

Reputation: 665344

If I replace someForeverPromise with a timer and then try to access the array contents they are still there

Your someForeverPromise itself was garbage-collected, and with it all the callbacks that were still waiting for it - including the resumption of the async function.

You can use

const foreverPendingPromise = new Promise(resolve => {
    global.reference = resolve;
});

where the global reference keeps up a way to resolve the promise to prevent the callbacks from being garbage-collected. (You also should make sure that no-one accidentally calls reference to ensure it stays pending, but I'll leave that as an exercise to the reader).

Upvotes: 1

Related Questions