真正有效的资源释放需主动解除媒体关联并重置状态:video需pause()、清空src、调用load()及revokeObjectURL(blob场景),并停止srcObject轨道;AudioContext须close()而非仅suspend();验证需观察chrome://task-manager和chrome://media-internals。

暂停播放后仅调用 pause() 并不能释放底层解码器、GPU 纹理或 MediaStream 轨道——这些资源仍被绑定在原生媒体对象上,尤其当 src 或 srcObject 未清空时,浏览器会维持缓冲区和解码上下文,造成“类非托管泄漏”。真正有效的切断方式,是主动解除 HTML 元素与媒体源的关联,并触发内部状态重置。
Video 标签:暂停后必须清空 src + load + revoke
对 <video> 元素,pause() 只暂停解码/渲染,不释放资源。需按顺序执行以下三步:
-
先暂停并清空 src:
video.pause(); video.src = ''; -
强制重置加载状态:
video.load();—— 这会中止当前加载、丢弃已缓存的片段、关闭解码器实例 -
若曾用 URL.createObjectURL() 创建 blob URL,必须显式回收:
URL.revokeObjectURL(video.src);(注意:此步仅适用于 blob URL 场景,普通 HTTP URL 不需要)
若视频曾绑定 srcObject(如来自摄像头或屏幕共享),还需额外停止所有轨道:if (video.srcObject) { video.srcObject.getTracks().forEach(t => t.stop()); video.srcObject = null; }
AudioContext:暂停 ≠ 停止,需 suspend + close
AudioContext 不是媒体标签,但其泄漏逻辑类似:调用 suspend() 仅暂停时间推进和节点处理,内部音频设备句柄、DSP 缓冲、Web Audio 线程仍存活。彻底释放需:
-
先 suspend(可选,用于过渡):
audioCtx.suspend(); -
再 close(关键动作):
audioCtx.close();—— 此操作不可逆,会销毁所有节点、释放音频硬件访问权、清空内部缓冲队列 -
确保无闭包强引用该 context:检查是否被定时器、事件监听器或全局变量长期持有;关闭后避免再访问
audioCtx.state或调用任何方法,否则会报错
验证是否真正断连
光写代码不够,得看底层资源是否回落:
- 打开
chrome://task-manager,观察 “Media memory” 和 “GPU memory” 是否在操作后明显下降 - 访问
chrome://media-internals,筛选对应 video/audio id,确认其state变为ended或消失,而非卡在paused或decoding - 若使用
MediaSource,调用mediaSource.endOfStream()后,再执行上述src = '' + load()才算完整收尾
常见误区提醒
以下操作看似合理,实则无效甚至加重泄漏:
- 只设
video.style.display = 'none'或remove()而不清空src—— 元素虽不可见或离 DOM,但解码器仍在后台运行 - 反复赋新
src却不先pause()和load()—— 旧流未终止,新流叠加,内存持续增长 - 认为
audioCtx.suspend()等价于释放 —— 它只是暂停,context 对象本身仍占内存,且可能阻止 GC 回收关联的 AudioNode

















