当前位置: 首页 > news >正文

canvas 正在慢慢吃掉你的内存...

canvas 概述

canvas 是一个可以通过 JavaScript 脚本来绘制图形的 HTML 元素,通常我们可以通过 canvas 来绘制图表、制作构图或者简单的动画。

与 canvas 的偶遇

在最近开发工作中,我最经常使用到 canvas 的场景是拿到已知的图片 URL,利用 canvas.toDataURL() 方法,将其转换为 base64 的图片格式。

除此之外,canvas 提供了 toBlob() 方法来创建 Blob 对象,这意味着,我们可以利用 canvas 将图片 URL 转换为 Blob 对象。

由此可见,当需要通过图片 URL 来转换为其他图片形式,我们就得经常和 canvas 打交道。

canvas 内存限制

如果你对 canvas 并不了解,就很容易忽略 canvas 的内存问题。当我看到这篇文章 mp.weixin.qq.com/s/hFG1ypsEc…,我才知道,如果 canvas 创建后没有及时回收,是会占用内存的,占用过多甚至会超出 canvas 内存限制,导致图片加载失败。

举个例子,如下面的代码,我们通过数组收集 canvas 对象,防止它被垃圾回收,并且声明一个创建 canvas 的方法,每个 canvas 宽高都为 512px,一个 canvas 所占用的内存即为 1MB:

html:

<div><span>内存单位: MB</span><input type="number" id="number" />
</div>
<div><button id="create">创建</button>
</div> 

JavaScript:

// 创建数组收集canvas,防止被垃圾回收
let canvasQueue = [];

// 创建 1MB canvas
const create1MCanvas = () => {const size = 512;const canvas = document.createElement("canvas");canvas.width = size;canvas.height = size;const context = canvas.getContext("2d");context.fillRect(0, 0, size, size);return canvas;
};

// 创建 n 个 1MB 的 canvas
const createNMCanvas = (n) => {for (let i = 0; i < n; i++) {canvasQueue.push(create1MCanvas());}
};

const input = document.querySelector("#number");
const button = document.querySelector("#create");

button.addEventListener("click", (event) => {event.preventDefault();const number = input.value;if (!Number.isNaN(Number(number))) {canvasQueue = [];createNMCanvas(Number(number));console.log(`创建${number}MB canvas成功`);}
}); 

接下来,我们创建 1000 个 canvas,也就是增加 1GB 内存,看看 GPU 的内存占用情况~

嗯,如你所见,内存占用确实妥妥增加 1GB 的内存,canvas 对内存确实存在肉眼可见的影响,canvas 可存放多少就取决于计算机设备的情况了,只要设备足够 nb,就能吃得下。比如我的笔记本设备是 16GB 的运行内存,当我增加 10GB 的canvas 时,页面就开始出现卡顿,这说明此时的计算机面对 10GB 内存的增加显得有些吃力。

canvas 清除行动

因为上面的例子中,每次循环都创建了 canvas 变量,并且通过数组收集,使其不被回收。JS 会在创建变量时为其自动分配内存,在不使用的时候自动释放内存,释放过程就是「 垃圾回收机制」。

既然 canvas 没有被回收,那么我们怎么阻止 canvas 带来的内存消耗呢?

首先,我们只创建一个 canvas,每次循环在画布上绘制完图像后,对画布进行清理。并且去除掉对 canvas 的收集,使其被自动回收,因为在实际开发场景中,在图像绘制完成后我们已经拿到了想要的东西,canvas 已经没啥用了,可以抛弃了。

修改代码如下:

let canvasQueue = [];
let canvas = document.createElement("canvas");
const size = 512;
canvas.width = size;
canvas.height = size;
const context = canvas.getContext("2d");

// 创建 n x 1MB canvas
const createNMCanvas = (n) => {for (let i = 0; i < n; i++) {context.fillRect(0, 0, size, size);// 绘制完后,在这里去拿我们想要的数据 如转换后的 base64 编码// context.drawImage(image, 0, 0, w, h);// const base64 = canvas.toDataURL('image/png')// 清除画布context.clearRect(0, 0, size, size);}
}; 

此时,我们增加难度,创建 2GB 的 canvas ,我们可以发现对计算机的内存占用几乎毫无波澜,并且页面也不会出现卡顿或者崩溃的现象。

写在最后

在实际开发中,我们更多是利用 canvas 来对图片做一些转换操作,这对内存并无影响,但如果创建 canvas 数量多的话,一定要注意 canvas 的最大内存限制问题。很多不起眼的代码,对内存却有着肉眼可见的影响,在开发中多注意 CPU、内存的使用情况和性能指标,有利于增加我们代码的健硕性和稳定性。

整理了一套《前端大厂面试宝典》,包含了HTML、CSS、JavaScript、HTTP、TCP协议、浏览器、VUE、React、数据结构和算法,一共201道面试题,并对每个问题作出了回答和解析。

有需要的小伙伴,可以点击文末卡片领取这份文档,无偿分享

部分文档展示:



文章篇幅有限,后面的内容就不一一展示了

有需要的小伙伴,可以点下方卡片免费领取

相关文章:

  • 【无标题】11111
  • go pprof 的使用
  • 类和对象 中
  • LeetCode变位词组
  • locust压测实例
  • 8.6 轻量化网络设计概述
  • 【C#】萌狼学习C#那年写的笔记汇总
  • 20个js工具函数助力高效开发
  • 软件领域中面向对象的设计模式
  • 01用户登录,登出,token等框架说明
  • 几位阿里发布这份内部MySQL性能优化法则笔记
  • java-php-python-ssm巢院小区疫情管控系统计算机毕业设计
  • Linux基础 - 系统安全(SELinux与Firewalld)
  • 学完这份“顶级”SpringCloudAlibaba笔记,微服务竟如此简单
  • Spring注解驱动开发及源码解析
  • 《Javascript高级程序设计 (第三版)》第五章 引用类型
  • git 常用命令
  • HashMap ConcurrentHashMap
  • Java知识点总结(JDBC-连接步骤及CRUD)
  • js操作时间(持续更新)
  • PHP 小技巧
  • PHP变量
  • python_bomb----数据类型总结
  • Redis中的lru算法实现
  • 你真的知道 == 和 equals 的区别吗?
  • 软件开发学习的5大技巧,你知道吗?
  • 设计模式走一遍---观察者模式
  • 使用API自动生成工具优化前端工作流
  • 使用common-codec进行md5加密
  • 腾讯大梁:DevOps最后一棒,有效构建海量运营的持续反馈能力
  • 我的业余项目总结
  • 线性表及其算法(java实现)
  • 一道闭包题引发的思考
  • 移动互联网+智能运营体系搭建=你家有金矿啊!
  • 异常机制详解
  • 关于Kubernetes Dashboard漏洞CVE-2018-18264的修复公告
  • 函数计算新功能-----支持C#函数
  • #define,static,const,三种常量的区别
  • #ifdef 的技巧用法
  • #绘制圆心_R语言——绘制一个诚意满满的圆 祝你2021圆圆满满
  • #我与Java虚拟机的故事#连载14:挑战高薪面试必看
  • (2)(2.4) TerraRanger Tower/Tower EVO(360度)
  • (a /b)*c的值
  • (二十四)Flask之flask-session组件
  • (生成器)yield与(迭代器)generator
  • (十五)Flask覆写wsgi_app函数实现自定义中间件
  • (原)记一次CentOS7 磁盘空间大小异常的解决过程
  • (转)关于如何学好游戏3D引擎编程的一些经验
  • .[hudsonL@cock.li].mkp勒索加密数据库完美恢复---惜分飞
  • .Net CF下精确的计时器
  • .Net MVC + EF搭建学生管理系统
  • .net 设置默认首页
  • .Net6支持的操作系统版本(.net8已来,你还在用.netframework4.5吗)
  • .NET连接MongoDB数据库实例教程
  • .NET牛人应该知道些什么(2):中级.NET开发人员