ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

ECharts 内存泄漏排查:3 类泄漏信号定位 + 最小修复 + 上线前自检清单

ECharts 内存泄漏排查:3 类泄漏信号定位 + 最小修复 + 上线前自检清单 ECharts 内存泄漏排查3 类泄漏信号定位 最小修复 上线前自检清单【免费下载链接】echartsApache ECharts is a powerful, interactive charting and data visualization library for browser项目地址: https://gitcode.com/GitHub_Trending/echa/echarts页面越用越卡、内存曲线一路爬坡十有八九是这三类问题ECharts 实例没销毁、setOption数据只进不出、DOM 事件引用残留。读完带走两样东西一套两分钟出结论的内存快照排查 SOP和一份可直接勾的上线前自检清单。先问 3 个自检问题你的页面在不在泄漏不用上 DevTools先回答下面三个问题能答出是的任意一项基本就可以定性为泄漏。反复创建了吗轮播、分页、路由切换场景里是不是每次进来都echarts.init()一遍旧实例从没被dispose()过数据有上限吗实时推送的setOption数据数组是不是只 push 不删10 分钟后它比初始大了多少倍监听器有主有仆吗你addEventListener绑上去的函数在图表销毁前被removeEventListener摘下来过吗三类问题对应三个泄漏源头实例生命周期、数据增长、引用残留。下面逐一给信号和最小修复。实例生命周期未闭环每个 init 都要有对应的 dispose结论泄漏信号是快照里同时存在多个__ec__前缀的 ECharts 实例对象。一个 DOM 容器同一时刻只需要一个实例重复init而不销毁旧的 model、view、zrender 渲染层全部留在堆里。错误写法是每次调用都init旧实例无处释放正确写法就一行判断let chart; function render() { if (chart) chart.dispose(); // 关键先销毁旧实例再 init chart echarts.init(document.getElementById(main)); chart.setOption(option); }一个容易混淆的点clear()和dispose()不是一回事。看 src/core/echarts.ts 的源码dispose()会把_model、_chartsViews、_zr、_messageCenter等内部引用全部置空并注销 DOM 上的实例标记实例从此可被 GC而clear()只是清空当前数据。另外实例dispose之后继续调用setOption/resize会直接触发源码里的disposedWarning所以销毁后还能用的想法不成立。自查点全局搜一下echarts.init(确认每一处都有对应的销毁路径组件卸载钩子、路由离开、轮播切换回调取决于你的框架。数据增长失控流式数据必须限长结论泄漏信号是setOption后堆内存台阶式上涨且涨完不回。实时场景里如果每次更新都把新点 push 进数组再整体setOption10 分钟后数据量可能是初始的几十倍series 数据、派生的 scale、layout 缓存全都跟着膨胀。最小修复是给数组定一个上限seriesData.push(newPoint); if (seriesData.length 500) seriesData.shift(); // 滚动窗口总量恒定 chart.setOption({ series: [{ data: seriesData }] }, { silent: true }); // silent 跳过动画与事件降开销配套两条经验高频更新加silent: true减少动画和事件触发的额外开销参数定义见 src/core/echarts.ts 的SetOptionOpts大数据集优先用appendData分片喂数据而不是把几十万点一次性塞进data。自查点问一句我的数据数组最大会到多少答不上来的就是事故。引用残留直接绑 DOM 的监听器dispose 管不了你结论泄漏信号是快照搜索某个回调函数名发现它被一个早已不可见的图表实例持有。ECharts 自己的事件chart.on(click, handler)走的是 src/core/echarts.ts 中基于Eventful的事件系统dispose时随实例一起释放一般不用操心。但如果你绕过它直接在 DOM 上addEventListener这个引用链条就完全归你管——图表销毁了监听器还攥着闭包里的实例不放。最小修复是存引用、成对拆const handler (e) { /* ... */ }; chart.getDom().addEventListener(mousemove, handler); // 销毁前成对移除 chart.getDom().removeEventListener(mousemove, handler); chart.dispose();window 上的resize监听同理要么resize回调里加防抖要么在图表销毁时一并removeEventListener——否则每次窗口缩放都白白触发一次已无意义的全量重绘。自查点搜addEventListener每一处都应有对称的removeEventListener。一次完整的排查动作 SOP内存快照对比法结论标准先说清楚操作前后各拍一张快照#Delta列里 ECharts 相关对象增量趋近于 0 即正常持续上涨即泄漏。全程 5 步F12 打开 Chrome DevTools切到 Memory 面板点Take heap snapshot拍基线。此时看到的就是初始占用记下总堆大小即可绝对值不重要。在页面里执行一轮典型操作创建图表 → 切换 3~5 个图表/路由 → 触发若干次setOption→ 离开页面。正常情况内存小幅波动。再拍一张快照打开两次快照的对比视图按Retained Size降序排。在过滤框输入ECharts或__ec__正常页面这里应该只有当前存活的实例0 或 1 个若看到已销毁页面残留的实例对象且#Delta为持续正数泄漏实锤。对可疑实例看 Retainers 链链上挂着data大数组 → 归到第二类数据增长挂着handler函数 → 归到第三类引用残留实例本身成堆 → 归到第一类未 dispose。辅助判断Performance 面板录 10 秒帧率稳定在 50fps 以上、主线程无持续 100ms 以上长任务说明还没到卡到怀疑人生的程度帧率跟着内存一起恶化时优先修第一类和第三类。上线前自检清单逐条勾完再发布5 分钟的事每个echarts.init(都有对应的dispose()销毁路径组件卸载 / 路由离开 / 轮播切换钩子dispose后没有继续对旧实例调setOption/resize/on源码会发 disposedWarning流式 / 增量数据数组有明确长度上限超限裁剪高频setOption场景使用了silent: true或合并更新所有addEventListener都有成对removeEventListenerresize监听带防抖快照对比创建 → 更新 → 销毁后ECharts 对象#Delta归零排查口诀就一句先 dispose 再 init数据要限长监听成对拆快照对 Delta。延伸阅读dispose实现src/core/echarts.tssetOption选项定义silent/notMergesrc/core/echarts.ts事件系统on/off入口src/core/echarts.ts官方文档dispose / setOption 章节Apache ECharts 官网【免费下载链接】echartsApache ECharts is a powerful, interactive charting and data visualization library for browser项目地址: https://gitcode.com/GitHub_Trending/echa/echarts创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表