繁体   English   中英

等待但从未解决/拒绝承诺内存使用

[英]Awaited but never resolved/rejected promise memory usage

是否会await一个既不解决也不拒绝(从未解决/未实现)的Promise导致内存泄漏?

我对此感到好奇,同时看着React钩子与slorber / awesome-debounce-promise创造新的承诺,但只能解决它们中的最后一个,从而留下许多/最不安/未实现。

前言(你可能知道这个!):

await是使用promise回调的语法糖。 (真的,真的,非常好的糖。) async函数是一个函数,其中JavaScript引擎构建了承诺链等等。

回答:

相关的问题不在于承诺是否得到解决,而是承诺回调(以及它们引用/关闭的东西)是否保留在内存中。 虽然承诺在内存中并且未解决,但它引用了它的回调函数,将它们保存在内存中。 有两件事让这些引用消失了:

  1. 解决诺言,或
  2. 发布对promise的所有引用,这使其符合GC的条件(可能在下面更多)

在正常情况下,promise的使用者将处理程序挂钩到promise,然后根本不保留对它的引用,或者仅在处理程序函数关闭而不是其他地方的上下文中保留对它的引用。 (而不是,例如,将promise引用保存在长期存在的对象属性中。)

假设debounce实现释放了对它永远不会解决的承诺的引用,并且promise的使用者没有在这个相互引用循环之外的某个地方存储引用,那么promise和处理程序注册到它(以及任何他们持有唯一的参考)一旦释放了对promise的引用,就可以全部收集垃圾。

这需要在实施方面给予相当多的关注。 例如(感谢Keith标记这一点) ,如果promise使用其他API的回调(例如, addEventListener )并且回调关闭对promise的引用,因为其他API具有对回调的引用,可以防止释放对promise的所有引用,从而在内存中保留promise所引用的任何内容(例如其回调)。

所以这取决于实施是否谨慎,以及消费者的一点点。 有可能编写能够保留对promises的引用的代码,从而导致内存泄漏,但在正常情况下,我不希望消费者这样做。

我使用以下结构进行了一些测试:

function doesntSettle() {
    return new Promise(function(resolve, reject) {
        // Never settle the promise
    });
}

let awaited = 0;
let resolved = 0;

async function test() {
    awaited++;
    await doesntSettle();
    resolved++;
}

setInterval(() => {
    for (let i = 0; i < 100; ++i) {
        test();
    }
}, 1);

在这里实现: https//codesandbox.io/s/unsetteled-awaited-promise-memory-usage-u44oc

在谷歌浏览器中运行结果框显示开发工具内存选项卡(但不在Performance / JS堆选项卡下)不断增加内存使用量,表明存在泄漏。 运行此但解决承诺没有泄漏。

运行这个增加的内存使用量增加了1-4MB /秒。 停止它并运行GC并没有释放任何它。

谷歌Chrome开发工具内存选项卡显示增加使用量

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM