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

使用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对象。

咨询问题

  1. 如何降低填充/绘制操作的内存占用?canvg有没有清除旧图层的函数?
  2. 需要保留撤销功能,怎么像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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.28 05:37:01