使用canvg的Canvas随编辑次数增加变慢/内存占用攀升问题咨询
关于canvg 3.x内存优化与撤销逻辑的问题
我用canvg 3.x开发了一款科学应用,用来测量扫描纸张上图形的面积。在Chrome里基本正常,但多次选择小区域后会变得非常卡顿。
核心代码片段
初始化canvg:
var s = canvg('canvas', inp_xmls, {ignoreMouse: true, ignoreAnimation: true});
桶填充操作:
var bucket = Bucket(canvas, cfg, event, color);
更新图像逻辑:
var lowerimg = svg.image(can.toDataURL()); lowerimg.node.onload = function () { drawDown();
重绘与撤销函数:
function drawDown() { inp_xmls = XMLS.serializeToString(svg.node); s.loadXml(ctx, inp_xmls); s.stop(); } function undo() { var last = svg.last(); if(svg.index(last) > 1) { last.remove(); drawDown(); s.draw(); } undoAddArea(); }
内存问题现象
通过内存快照发现,strings、image和#document的内存占用显著增加,每次绘制都会新增src对象。
咨询问题
- 如何降低填充/绘制操作的内存占用?canvg有没有清除旧图层的函数?
- 需要保留撤销功能,怎么像undo函数那样访问旧图像,删除早于5次编辑的内容?
解决方案
问题1:降低内存占用
- 避免重复创建SVG节点/图像对象:你现在每次填充后都用
svg.image(can.toDataURL())新增图像节点,旧节点若未彻底清理会持续占用内存。建议复用同一个底层画布,而非每次新增图像层。 - 手动清理画布上下文:canvg 3.x没有专门的"清除旧图层"函数,但可在每次
loadXml前清空画布上下文,避免旧内容残留:function drawDown() { // 清空画布,释放旧内容占用的内存 ctx.clearRect(0, 0, canvas.width, canvas.height); inp_xmls = XMLS.serializeToString(svg.node); s.loadXml(ctx, inp_xmls); s.stop(); } - 释放无用Image对象:当旧的
lowerimg不再需要时,手动设置lowerimg.node.src = '',让浏览器可以回收这部分内存,避免内存泄漏。 - 减少SVG序列化频率:每次
XMLS.serializeToString都会生成新的大字符串,这也是strings内存增长的核心原因。建议直接操作canvg内部的SVG对象,而非反复序列化、加载。
问题2:限制撤销历史数量(保留最近5次编辑)
- 维护固定长度的历史栈:不要依赖SVG节点顺序管理撤销,单独用数组存储最近5次的SVG状态(序列化字符串或SVG节点副本):
// 初始化历史栈,最多存储5条记录 const undoStack = []; const MAX_UNDO_COUNT = 5; // 每次填充操作完成后,保存当前SVG状态 function saveUndoState() { const currentState = XMLS.serializeToString(svg.node); undoStack.push(currentState); // 超过最大数量时,删除最早的一条记录 if (undoStack.length > MAX_UNDO_COUNT) { undoStack.shift(); } } // 修改undo函数,从历史栈读取状态恢复 function undo() { if (undoStack.length > 0) { const lastState = undoStack.pop(); inp_xmls = lastState; s.loadXml(ctx, inp_xmls); s.draw(); undoAddArea(); } } - 清理旧SVG节点:当删除早于5次的编辑内容时,要同步从DOM中移除对应的旧图像节点并解除引用,避免这些节点持续占用内存。
内容的提问来源于stack exchange,提问作者mnzl
相关产品推荐
相关产品推荐

