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

ChartJS加载大量数据时内存溢出及保留图表的内存清理方案咨询

问题原因排查

你目前的内存溢出问题核心是每次调用barChart函数都会新建一个Chart实例,旧实例没有被正确销毁,相关的数据集、事件监听、Canvas上下文资源会持续占用内存,累计到一定阈值就会触发Chrome的内存不足报错。

解决方案

分两种场景适配:

场景1:不需要保留图表交互能力(不需要hover提示、点击交互等)

这种场景可以完美实现「释放内存+保留图表显示」的需求,思路是将渲染完成的图表转为静态图片,再销毁Chart实例:

// 全局变量存实例,也可以存在window对象上避免污染全局
let barChartInstance = null;

function barChart(barChartVal) {
    const chartDom = document.getElementById("chart-area-last-5-runs");
    // 先销毁已存在的旧实例
    if (barChartInstance) {
        barChartInstance.destroy();
        barChartInstance = null;
    }
    const color = new chartColor();
    barChartInstance = new Chart(chartDom, {
        type: 'bar',
        data: {
            labels: [barChartVal[5][0], barChartVal[5][1], barChartVal[5][2], barChartVal[5][3], barChartVal[5][4]],
            datasets: [{
                data: [barChartVal[0][0], barChartVal[0][1], barChartVal[0][2], barChartVal[0][3], barChartVal[0][4]],
                label: 'Passed',
                backgroundColor: color.green(),
            }, {
                data: [barChartVal[1][0], barChartVal[1][1], barChartVal[1][2], barChartVal[1][3], barChartVal[1][4]],
                label: 'Failed',
                backgroundColor: color.red(),
            }, {
                data: [barChartVal[2][0], barChartVal[2][1], barChartVal[2][2], barChartVal[2][3], barChartVal[2][4]],
                label: 'Error',
                backgroundColor: color.yellow(),
            }, {
                data: [barChartVal[3][0], barChartVal[3][1], barChartVal[3][2], barChartVal[3][3], barChartVal[3][4]],
                label: 'Not Run',
                backgroundColor: color.blue(),
            }, {
                data: [barChartVal[4][0], barChartVal[4][1], barChartVal[4][2], barChartVal[4][3], barChartVal[4][4]],
                label: 'Not Applicable',
                backgroundColor: color.black(),
            }]
        },
        options: {
            scales: {
                xAxes: [{
                    stacked: true,
                    ticks: {
                        display: false
                    }
                }],
                yAxes: [{ stacked: true }]
            },
            tooltips: {
                mode: 'index',
                intersect: false,
                titleFontSize: 14,
                bodyFontSize: 13,
                bodySpacing: 0,
                titleSpacing: 0,
                xPadding: 2,
                yPadding: 2,
                cornerRadius: 2,
                titleMarginBottom: 2
            },
            hover: {
                mode: 'index',
                intersect: false
            },
            animation: false,
            parsing: false,
            normalized: true
        },
        // 渲染完成钩子
        plugins: [{
            afterRender: function(chart) {
                // 转成静态图片
                const imgUrl = chart.toBase64Image();
                // 替换canvas为img
                const img = document.createElement('img');
                img.src = imgUrl;
                img.alt = "统计柱状图";
                img.style.width = chart.width + 'px';
                img.style.height = chart.height + 'px';
                chartDom.parentNode.replaceChild(img, chartDom);
                // 销毁实例释放所有内存
                chart.destroy();
                barChartInstance = null;
            }
        }]
    });
}

场景2:需要保留图表交互能力

这种情况不能销毁实例,需要通过单实例管理避免内存泄露:

let barChartInstance = null;

function barChart(barChartVal) {
    const chartDom = document.getElementById("chart-area-last-5-runs");
    const color = new chartColor();
    const chartData = {
        labels: [barChartVal[5][0], barChartVal[5][1], barChartVal[5][2], barChartVal[5][3], barChartVal[5][4]],
        datasets: [{
            data: [barChartVal[0][0], barChartVal[0][1], barChartVal[0][2], barChartVal[0][3], barChartVal[0][4]],
            label: 'Passed',
            backgroundColor: color.green(),
        }, {
            data: [barChartVal[1][0], barChartVal[1][1], barChartVal[1][2], barChartVal[1][3], barChartVal[1][4]],
            label: 'Failed',
            backgroundColor: color.red(),
        }, {
            data: [barChartVal[2][0], barChartVal[2][1], barChartVal[2][2], barChartVal[2][3], barChartVal[2][4]],
            label: 'Error',
            backgroundColor: color.yellow(),
        }, {
            data: [barChartVal[3][0], barChartVal[3][1], barChartVal[3][2], barChartVal[3][3], barChartVal[3][4]],
            label: 'Not Run',
            backgroundColor: color.blue(),
        }, {
            data: [barChartVal[4][0], barChartVal[4][1], barChartVal[4][2], barChartVal[4][3], barChartVal[4][4]],
            label: 'Not Applicable',
            backgroundColor: color.black(),
        }]
    };
    // 实例已存在则直接更新数据,不需要新建
    if (barChartInstance) {
        barChartInstance.data = chartData;
        barChartInstance.update();
        return;
    }
    // 不存在则新建实例
    barChartInstance = new Chart(chartDom, {
        type: 'bar',
        data: chartData,
        options: {
            scales: {
                xAxes: [{
                    stacked: true,
                    ticks: {
                        display: false
                    }
                }],
                yAxes: [{ stacked: true }]
            },
            tooltips: {
                mode: 'index',
                intersect: false,
                titleFontSize: 14,
                bodyFontSize: 13,
                bodySpacing: 0,
                titleSpacing: 0,
                xPadding: 2,
                yPadding: 2,
                cornerRadius: 2,
                titleMarginBottom: 2
            },
            hover: {
                mode: 'index',
                intersect: false
            },
            animation: false,
            parsing: false,
            normalized: true
        }
    });
}

// 可选:监听标签页隐藏事件临时销毁实例,切回时重新渲染,进一步降低后台内存占用
document.addEventListener('visibilitychange', () => {
    if (document.hidden && barChartInstance) {
        // 隐藏时销毁
        barChartInstance.destroy();
        barChartInstance = null;
    } else if (!document.hidden) {
        // 显示时重新调用barChart传入最新数据即可
        // barChart(最新的barChartVal);
    }
});
额外优化建议
  • 大数据量场景下可以对数据集做降采样,减少单图表的渲染数据量
  • 确认不需要的交互、动画功能都关闭,降低运行时内存开销

内容的提问来源于stack exchange,提问作者Mads Sander Høgstrup

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.23 17:06:02