You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React中用jsmpeg播放多RTSP流时出现Too many active WebGL contents问题求助

RTSP流渲染内存泄漏问题(Too many active WebGL contents)解决

问题本质

这个警告是浏览器提示当前页面活跃的WebGL上下文数量已接近上限。浏览器对单标签页的WebGL上下文数量有严格限制(一般在16-32个之间),你的25路流已经接近阈值,加上路由切换时旧的WebGL资源没彻底清理,就会触发该提示。这确实是内存泄漏问题,长期忽略会导致流无法渲染、页面卡顿甚至崩溃,必须修复。

现有代码的核心问题

  1. 全局streams变量:跨组件/实例共享资源,容易导致残留引用无法被垃圾回收(GC),组件卸载后全局变量仍会保留空引用。
  2. useEffect依赖缺失:挂载逻辑只执行一次,当preset(流列表/布局)变化时,旧播放器实例未被清理就创建新的,导致WebGL上下文堆积。
  3. elementsRef初始化逻辑错误:useRef的初始值不会随preset.partition变化更新,布局变化时canvas引用失效,旧canvas关联的WebGL资源无法释放。
  4. 卸载清理不彻底:仅把streams的值设为null,但对象键仍存在,残留空引用可能阻碍GC。

修复方案

1. 将全局streams移至组件内部

用useRef在组件内部存储播放器实例,避免全局变量的资源冲突:

// 替换全局streams,组件内部定义
const streams = useRef<Record<string, JSMpeg.Player | null>>({});

2. 修正canvas引用数组的更新逻辑

当布局分区数变化时,重新生成canvas引用数组,确保引用始终有效:

const elementsRef = useRef<(React.RefObject<HTMLCanvasElement>)[]>([]);

useEffect(() => {
  // 分区数变化时重置引用数组
  elementsRef.current = new Array(preset?.partition || 0).fill(0).map(() => createRef());
}, [preset?.partition]);

3. 监听preset变化,全生命周期管理播放器

修改核心逻辑,在preset变化时先清理旧播放器,再创建新的,同时确保卸载时彻底清理:

useEffect(() => {
  const { JSMpeg } = window;
  if (!preset?.stream) return;

  // 第一步:清理当前所有旧播放器
  Object.values(streams.current).forEach(player => {
    if (player) {
      player.destroy();
    }
  });
  streams.current = {};

  // 第二步:创建新播放器
  const sortedStream = _.sortBy(preset.stream, ["position"]);
  sortedStream.forEach(v => {
    const canvas = elementsRef.current[v.position]?.current;
    if (!canvas) return;
    const player = new JSMpeg.Player(v.camera_monitoring.ws, { canvas });
    streams.current[v.id] = player;
  });

  // 组件卸载时的清理逻辑
  return () => {
    Object.values(streams.current).forEach(player => {
      if (player) {
        player.destroy();
      }
    });
    streams.current = {};
  };
}, [preset]); // 依赖preset,流列表或布局变化时自动执行

4. 彻底清理资源

卸载时不仅调用destroy(),还要清空streams对象,确保无残留引用阻碍垃圾回收。

5. 额外优化:降低WebGL上下文占用

25路流同时渲染已接近浏览器上限,可做以下优化:

  • 按需播放:只渲染可见区域的流,不可见时调用player.pause()暂停,需要时再恢复播放,减少活跃WebGL上下文数量。
  • 资源复用:若JSMpeg支持,尝试复用WebGL上下文(单实例绑定一个canvas,复杂度较高,需结合业务场景评估)。

内容的提问来源于stack exchange,提问作者jerry

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.12 01:05:45