JavaScript 中 await 永远不会 resolve 的 Promise 会导致内存泄露吗?

前言

在 JavaScript 中,await 关键字用于等待一个 Promise 完成,它只能在异步函数(async function)内部使用。当 await 一个永远不会 resolve 的 Promise 时,它确实会阻塞异步函数的进一步执行,但不会直接导致内存泄露(memory leak)。然而,这种情况可能会间接导致问题,特别是在处理资源(如数据库连接、文件句柄、网络请求等)时。

为什么说它不会直接导致内存泄露?

内存泄露通常指的是程序在不需要某些内存时未能释放它,导致内存使用量持续增加。在 JavaScript(特别是在 V8 引擎中,Chrome 和 Node.js 的 JavaScript 引擎)中,垃圾回收器(Garbage Collector, GC)会定期清理不再被引用的对象。如果一个 Promise 永远不会 resolve,那么它自身及其依赖的对象(除非有其他引用指向它们)最终会因为没有任何引用指向它们而被垃圾回收器回收。

间接问题

尽管 await 一个永远不会 resolve 的 Promise 不会直接导致内存泄露,但它可能导致以下问题:

  1. 阻塞执行:异步函数将停留在 await 表达式处,无法继续执行后续代码,这可能会阻塞事件循环中的其他任务。

  2. 资源占用:如果 Promise 依赖于某些外部资源(如数据库连接、文件句柄、网络请求等),这些资源将不会被释放,直到 Promise 被解决或拒绝。如果 Promise 永远不解决,这些资源可能会长时间被占用,甚至可能导致资源耗尽。

  3. 死锁和性能问题:在复杂的应用程序中,多个异步操作可能相互依赖。如果一个操作因为等待一个永远不会 resolve 的 Promise 而阻塞,它可能会阻止其他依赖它的操作执行,从而导致死锁或性能问题。

想要知道 promise 对象有没有被回收掉,可以在控制台使用 queryObjects() :

queryObjects(Promise) 做的是就是先手动执行一次垃圾回收,然后输出当前页面内存里还存在的 promise 对象。有 0 个,证明所有的 promise 对象都已经被回收了。

为了更明确的看到回收的确发生了,我们还可以给传入 test() 的 promise 对象和 test() 返回的 promise 对象都添加上垃圾回收的回调:

可以看到,这两万个永远不会 resolve 的 promise 都被回收了,这也是符合预期的。

JS 标准应该没有制定垃圾回收的具体细节,任何的对象何时被回收,甚至完全不回收,可能都不算是违反规范,毕竟 test262 里没有相关测试。不过规范实际制定时肯定还是要考虑逻辑上不能存在内存泄漏的。

所以这些都是引擎实现的知识,只有少数引擎开发能讲清楚这些细节,我只知道一点皮毛,下面是我的推测。

想要一个对象不被回收,必须有地方引用了它,除了直接引用,还可以间接的引用,比如:

new Promise((resolve, reject) => { window.foo = resolve 
})

因为全局变量 foo 引用了 resolve 函数,这个函数比较特殊,在 C++ 层面其实引用了它所属的 promise 对象,所以会导致 promise 对象一直可达(reachable),也就无法被垃圾回收。

new Promise(resolve => {setTimeout(resolve, 10000)
})

像这个 promise,在 10 秒后才会被垃圾回收,10 秒内全局的任务队列里有个定时器任务引用了它,定时器执行完销毁后,这个 promise 对象就变成不可达的,从而也就被回收了。

如果 resolve 和 reject 都没被引用,它就会被直接回收掉:

new Promise(() => {})

除非有其它引用,比如你示例里的 p:

async function test(p) {await p
}test(new Promise(() => {}))

这个局部变量 p 的确引用了 promise 对象,那这个 promise 被回收只有一个可能,就是 p 也不在了,实际上的确是,这个 test 函数的执行上下文也被回收了,虽然它还没执行完。

实际上 V8 的 async function 在 parser 阶段是被 desugar 成 generator 的 https://docs.google.com/document/d/1K38ct2dsxG_9OfmgErvFld4MPDC4Wkr8tPuqmSWu_3Y/edit,所以 test 函数在实际执行时可能类似于:

function* test(p) {yield pconsole.log(p)
}test(new Promise(() => {}))

生成器在 yield p 这里停住,就类似于 await p 停住,因为已经没有办法引用到生成器的 next() 方法了,引擎就知道它不可能继续执行了,从而就一连串回收掉了所有的相关对象,具体的细节我是讲不清楚的。

解决方案

  • 超时机制:为 await 操作设置超时,以便在 Promise 无法在指定时间内 resolve 时采取适当的行动(如重试、记录错误或释放资源)。

  • 错误处理:确保 Promise 的错误处理逻辑是健全的,以便在 Promise 被拒绝时能够适当响应。

  • 资源清理:确保所有外部资源在使用完毕后都被正确释放,无论 Promise 是否 resolve。

  • 监控和日志:对异步操作进行监控,并在出现问题时记录详细的日志,以便快速定位和解决问题。

总之,虽然 await 一个永远不会 resolve 的 Promise 不会直接导致内存泄露,但它可能导致其他严重的问题,因此应该避免这种情况的发生。

仅供参考!!!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/46270.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Matlab中产生高斯白噪声信号的方法和其功率计算

Matlab中产生高斯白噪声信号的方法和其功率计算 matlab中计算信号能量: p o w e r ∑ n 1 N x 2 ( n ) power \sum_{n1}^Nx^2(n) powern1∑N​x2(n) ​ 功率为 P 1 N ∑ n 1 N x 2 ( n ) P \frac{1}{N}\sqrt{\sum_{n1}^Nx^2(n)} PN1​n1∑N​x2(n) ​ 对应ma…

C1W1.Assignment: Logistic Regression

理论课:C1W1.Sentiment Analysis with Logistic Regression 文章目录 前期准备导入包导入数据处理推文文本 Part 1: Logistic regressionPart 1.1: Sigmoid实现 sigmoid 函数Logistic regression: regression and a sigmoid Part 1.2 Cost function and GradientUp…

Python 使用proto 发送socket数据

import socket import binascii import struct from SensingMonitoring_pb2 import Command, CommandNamesif __name__ "__main__":client socket.socket(socket.AF_INET, socket.SOCK_STREAM)client.connect(("192.168.1.100", 22295))# 发送数据comman…

软件模块的初始化

什么是初始化? 软件的初始化(Initialization)是指软件启动或重新配置时执行的一系列步骤和过程,旨在准备软件运行环境、加载必要的配置信息、检查系统依赖项、分配资源(如内存、文件句柄等),以及…

Microsoft Build 2024 推出 .NET 9:Tensor<T>、 OpenAI Collaboration和.NET Aspire

在 Microsoft Build 2024 上,.NET 9 4 发布,引入了用于深度学习的 Tensor 类型以及与 OpenAI Collaboration实现GPT4o和Assistants v2等功能。这些最新改进还带来了 .NET Aspire,简化了云原生应用开发。更新涵盖 ASP.NET Core、Blazor 和 .NE…

5、Hacker_Kid-v1.0.1

中等难度 目标root权限 先进行一波IP地址发现 netdiscover -i eth0 -r 192.168.1.1/24 发现存在的靶机ip 进行一波端口的探测 发现是一个apache的服务和一个tornado的网站 这里有个细节部分,53端口常见的情况都是走的udp协议做的域名解析,这里查询出来…

【ARM】CCI缓存一致性整理

目录 1.CCI500提供的功能 2.CCI500在SOC系统中所处的位置​编辑 3.CCI500内部结构​编辑 4.功能描述 1.CCI500提供的功能 2.CCI500在SOC系统中所处的位置 3.CCI500内部结构 Transaction Tracker(TT)是用来解决一致性和ordering问题的,它…

完成SSH连接与端口映射并运行hello_world.py以及创建conda环境

完成SSH连接与端口映射并运行hello_world.py 第一步: 使用vscode打开连接开发机如图 第二步: 端口映射 ssh -p 37367 rootssh.intern-ai.org.cn -CNg -L {本地机器_PORT}:127.0.0.1:{开发机_PORT} -o StrictHostKeyCheckingno 如: ssh -…

牛客周赛51 F(静态区间最大连续子段和)

题面 题目地址 原题是SPOJ 1043。本文中我介绍的是维护前缀和的写法&#xff0c;如果你想要了解其他写法&#xff0c;可以搜索原题题解。 题目大意&#xff1a; 给定长度为n的数组a&#xff0c;q次查询&#xff0c;每次询问[l,r]中连续子段和的绝对值最大是多少 1 < n, q&l…

SpringBoot整合 Kaptcha 验证码

文章目录 1 Kaptcha 验证码1.1 引言1.2 Kaptcha1.2.1 pom.xml1.2.2 配置类1.2.2.1 Redis配置类RedisConfig1.2.2.2 验证码配置类KaptchaConfig 1.2.3 验证码控制层1.2.4 登录控制层 1 Kaptcha 验证码 1.1 引言 为防止验证系统被暴力破解&#xff0c;很多系统都增加了验证码效…

优化静止不动的GPS点(JS版)

1.理论依据: 连续的GPS点中&#xff0c;静止不动的一段或者多段这样的点序列。把这些点序列处理成一个点&#xff0c;也就是拿这些序列的第一个点即可。理论依据如下&#xff1a;从第二个点开始&#xff0c;每个点都和第一个点进行距离计算和比较。至少比较N个点。当百分之M的…

maven多模块项目打包构建的配置

使用背景&#xff1a; springbootmaven构建的多模块项目&#xff0c;没有使用springcloud&#xff0c;根项目下有多个module&#xff0c;一个module有springboot启动类&#xff0c;其他module没有启动类&#xff0c;作为module被有springboot启动类的module所引用。 1.根目录…

Win11任务栏当中对 STM32CubeMX 的堆叠问题

当打开多个 CubeMX 程序的时候&#xff0c;Win11 自动将其进行了堆叠&#xff0c;这时候就无法进行预览与打开。 问题分析&#xff1a;大部分ST的工具都是基于 JDK 来进行开发的&#xff0c;Win11 将其识别成了同一个 Binary 但是实际上他们并不是同一个&#xff0c;通过配置…

redis源码分析之底层数据结构(一)-动态字符串sds

1.绪论 我们知道redis是由c语言实现的&#xff0c;c语言中是自带字符串的&#xff0c;但是为什么redis还要再实现自己的动态字符串呢&#xff0c;这种动态字符串的底层数据结构是怎样的呢?接下来我们带着这些问题来看一看redis中的动态字符串sds。 2.sds的组成 struct __at…

pico+unity3d项目配置

重点&#xff1a;unity编辑器版本要和pico的sdk要求一致、比如&#xff1a; 对于 Unity 2022.1.14 及以上版本&#xff0c;若同时在项目中使用 URP、Linear 色彩空间、四倍抗锯齿和OpenGL&#xff0c;会出现崩溃。该问题待 Unity 引擎解决。对于 Unity 2022&#xff0c;若同时…

多个版本JAVA切换(学习笔记)

多个版本JAVA切换 很多时候&#xff0c;我们电脑上会安装多个版本的java版本&#xff0c;java8&#xff0c;java11&#xff0c;java17等等&#xff0c;这时候如果想要切换java的版本&#xff0c;可以按照以下方式进行 1.检查当前版本的JAVA 同时按下 win r 可以调出运行工具…

Pytorch张量

在conda的环境中安装Jupyter及其他软件包 Pytorch 建立在张量&#xff08;tensor&#xff09;之上&#xff0c;Pytorch张量是一个 n 维数组&#xff0c;类似于 NumPy 数组。专门针对GPU设计&#xff0c;可以运行在GPU上以加快计算效率。换句话说&#xff0c;Pytorch张量是可以运…

wget介绍

wget介绍 wget是一个广泛使用的命令行工具&#xff0c;主要用于从网络上自动下载文件。它支持HTTP、HTTPS和FTP等多种协议&#xff0c;具有递归下载、断点续传、限速下载等功能&#xff0c;使其成为一个强大而灵活的下载工具。以下是对wget的详细介绍和使用方法的概述&#xf…

解决QT creator中文乱码问题

1.首先设置文本编辑器为UTF-8 先在工具-选项-文本编辑器-behavior部分选择文件编码为UTF-8&#xff0c;紧接着是选择“如果编码是UTF-8则添加”&#xff0c;如下图 2.设置ext code for tools 为system 具体解决办法是 工具-选项-环境-interfaces这一栏有一个“Text code for to…