深入探索如何压缩 WebAssembly
一、初始体积:默认 Release 构建
我们从最基础的构建开始,不开启调试符号,仅使用默认的 release 模式:
$ wc -c pkg/wasm_game_of_life_bg.wasm
29410 pkg/wasm_game_of_life_bg.wasm
这是我们优化的起点 —— 29,410 字节。
二、启用 LTO + opt-level = “z” + wasm-opt -Oz
2.1. LTO(链接时间优化)
开启 LTO 能让 Rust 编译器在链接阶段进行跨 crate 优化,从而消除未使用的代码路径。
在 Cargo.toml 中配置:
[profile.release]
lto = true
opt-level = "z"
然后使用 wasm-opt 进一步压缩:
wasm-opt -Oz -o pkg/wasm_game_of_life_bg.wasm pkg/wasm_game_of_life_bg.wasm
$ wc -c pkg/wasm_game_of_life_bg.wasm
17317 pkg/wasm_game_of_life_bg.wasm
现在体积已缩减至 17,317 字节,减少了近 41%。
三、Gzip 压缩进一步优化网络传输
$ gzip -9 < pkg/wasm_game_of_life_bg.wasm | wc -c
9045
HTTP 服务器几乎都会自动启用 gzip 压缩,最终用户接收的 .wasm 文件仅 9,045 字节,相比最初几乎缩小了 70% 以上。
四、使用 wasm-snip 移除 panic 支持代码
Rust 编译时会在 .wasm 中生成 panic 相关函数,即便我们不实际用到。这部分可以通过 wasm-snip 移除:
wasm-snip pkg/wasm_game_of_life_bg.wasm -o pkg/snipped.wasm
这一操作通常可以节省数百到上千字节,具体节省视 panic 使用情况而定。以我的测试为例:
$ wc -c pkg/snipped.wasm
16532 pkg/snipped.wasm
节省了 785 字节!
五、引入 wee_alloc 迷你分配器
默认的全局内存分配器(如 jemalloc)在 .wasm 中占据了较大的空间,而 wee_alloc 是专门为 WebAssembly 优化的轻量级 allocator。
启用方式非常简单,只需在 Cargo.toml 中加入:
[features]
default = ["wee_alloc"]
然后在 lib.rs 中设置:
#[cfg(feature = "wee_alloc")]
#[global_allocator]
static ALLOC: wee_alloc::WeeAlloc = wee_alloc::WeeAlloc::INIT;
构建后 .wasm 大小进一步缩减。例如:
$ wc -c pkg/wasm_game_of_life_bg.wasm
15800 pkg/wasm_game_of_life_bg.wasm
相比使用系统 allocator,wee_alloc 又节省了 500~1,000 字节不等。
六、 完全移除动态内存:进入 #![no_std] 世界
Game of Life 实际上不需要动态分配任何内存:我们只维护一个单一的宇宙状态,可以将其定义为 static mut 全局变量。
这样做的好处是:
- 移除对 allocator 的依赖
- 支持
#![no_std]编译 - 完全控制内存布局
在 Cargo.toml 中:
[lib]
crate-type = ["cdylib"]
在 lib.rs 中:
#![no_std]
当我们完全剥离 allocator 依赖后,构建出的 .wasm 文件可以进一步减小:
$ wc -c pkg/wasm_game_of_life_bg.wasm
13300 pkg/wasm_game_of_life_bg.wasm
再加上 wasm-opt 和 gzip:
$ gzip -9 < pkg/wasm_game_of_life_bg.wasm | wc -c
7080
最终我们实现了从 29,410 → 7,080 字节 的极限压缩,整整缩小了 75.9%!
七、 小结:优化清单与效果对比
| 优化手段 | 大小(字节) | 相对初始减少 |
|---|---|---|
| 默认 release | 29,410 | 0% |
| LTO + opt-level = “z” + wasm-opt -Oz | 17,317 | -41.1% |
| 启用 gzip 压缩 | 9,045 | -69.2% |
| 移除 panic 基础设施(wasm-snip) | ~16,532 | -43.8% |
启用 wee_alloc | ~15,800 | -46.3% |
完全移除 allocator(#![no_std]) | ~13,300 | -54.8% |
| gzip 压缩后最终体积 | 7,080 | -75.9% |
八、结语
.wasm 文件并不是构建后就结束了,优秀的 WebAssembly 项目应像前端打包优化一样,关注体积、网络传输和运行性能。《生命游戏》这个案例为我们提供了实践场景:通过 LTO、wasm-opt、wee_alloc、wasm-snip、gzip 和 no_std,我们将文件压缩到了原来的四分之一以下。
相关文章:
深入探索如何压缩 WebAssembly
一、初始体积:默认 Release 构建 我们从最基础的构建开始,不开启调试符号,仅使用默认的 release 模式: $ wc -c pkg/wasm_game_of_life_bg.wasm 29410 pkg/wasm_game_of_life_bg.wasm这是我们优化的起点 —— 29,410 字节。 二…...
浅谈SQL Server系统内核管理机制
浅谈SQL Server系统内核管理机制 应用环境 Microsoft Windows 10.0.19045.5487 x64 专业工作站版 22H2Microsoft SQL Server 2019 - 15.0.2130.3 (X64)SQL Server Management Studio -18.6 laster 文章目录 浅谈SQL Server系统内核管理机制数据库和文件服务器管理视图系统目录…...
关于我的服务器
最近我买了台腾讯云服务器,然后新手小白只会用宝塔。。。 安装完之后默认的端口是8888,打开面板就会提示我有风险。然后 我改了端口之后,怎么都打不开。 于是 学到了几句命令可以使用: //查看端口是否已经修改成功 cat www/se…...
vue + element-plus自定义表单验证(修改密码业务)
写一个vue组件Password.vue 没有表单验证只有3个表单项 <template><div><el-form><el-form-item label"旧密码"><el-input></el-input></el-form-item><el-form-item label"新密码"><el-input>&l…...
2025年第十八届“认证杯”数学中国数学建模网络挑战赛【BC题】完整版+代码+结果
# 问题一:随机森林回归from sklearn.ensemble import RandomForestRegressormodel_rf RandomForestRegressor()model_rf.fit(X_train, y_train)# 问题二:LSTM时间序列预测from tensorflow.keras.models import Sequentialmodel_lstm Sequential()model…...
一、小白如何用Pygame制作一款跑酷类游戏(成品展示+添加背景图和道路移动效果)
小白如何用Pygame制作一款跑酷类游戏 文章目录 小白如何用Pygame制作一款跑酷类游戏前言一、游戏最终效果展示二、创建项目并加载pygame模块1.创建项目2.下载pygame模块3. 项目结构安排 三、添加背景图和实现道路移动效果1.引入库2.窗口设置和资源加载3.游戏主循环和程序入口4.…...
基础知识:Dify 安装
官方指南:https://docs.dify.ai/zh-hans/getting-started/install-self-hosted docker & docker-compose 安装 可参考:...
关闭谷歌浏览器(Google Chrome)的自动更新可以通过以下方法实现。具体操作步骤取决于你的操作系统。
关闭谷歌浏览器(Google Chrome)的自动更新可以通过以下方法实现。具体操作步骤取决于你的操作系统。 1. 在 Windows 上关闭 Chrome 自动更新2. 在 macOS 上关闭 Chrome 自动更新3. 在 Linux 上关闭 Chrome 自动更新4. 注意事项1. 在 Windows 上关闭 Chro…...
【MCAL】AUTOSAR架构下基于SPI通信的驱动模块详解-以TJA1145为例
目录 前言 正文 1.TJA1145驱动代码中的SPI协议设计 1.1 对SPI Driver的依赖 1.2 对SPI配置的依赖 1.2.1 SpiExternalDevice 1.2.2 Channel_x 1.2.3 Job_x 1.2.4 Sequence N 1.2.5 Sequence M 1.2.6 Sequence L 1.2.7 小结 2.基于Vector驱动代码的SPI配置 2.1 SPI引…...
如何在vue3项目中使用 AbortController取消axios请求
在 Vue3 项目中通过 AbortController 取消 Axios 请求,可以通过以下 结构化步骤 实现。我们结合组合式 API(Composition API)和现代前端实践演示: 一、基础实现(单个请求) 1. 创建组件逻辑 <script s…...
监控docker中的java应用
1)进入指定的容器 docker exec -it demo /bin/bash 2)下载curl root89a67e345354:/# apt install curl -y 3)下载arthas root89a67e345354:/# curl -O https://arthas.aliyun.com/arthas-boot.jar 4)运行 root89a67e345354:/# java -jar arthas-boot.jar 5)监控 […...
JWT令牌:实现安全会话跟踪与登录认证的利器
摘要:本文深入探讨了JWT令牌在实现会话跟踪和登录认证方面的应用,详细介绍了JWT令牌的概念、组成、生成与校验方法,以及在实际案例中如何通过JWT令牌进行会话跟踪和登录认证的具体实现步骤,为系统的安全认证机制提供了全面且深入的…...
VS 中Git 中本地提交完成,没有推送,修改的内容如何还原
在 Visual Studio 中撤销本地提交但未推送的修改,可以通过以下方法实现: 一、保留修改内容(仅撤销提交记录) 使用 git reset --soft 在 VS 的 Git 终端中执行: git reset --soft HEAD~1作用:撤销最后一次提…...
springboot+tabula解析pdf中的表格数据
场景 在日常业务需求中,往往会遇到解析pdf数据获取文本的需求,常见的做法是使用 pdfbox 来做,但是它只适合做一些简单的段落文本解析,无法处理表格这种复杂类型,因为单元格中的文本有换行的情况,无法对应到…...
Ubuntu18.04 ROS Melodic安装
环境配置:Ubuntu18.04 ROS Melodic安装_ubuntu18.04安装ros melodic-CSDN博客 1 设置安装源 为了安装ROS Melodic,首先需要在Ubuntu 18.04 LTS上添加安装源到source.list,方法如下: 国外的: sudo sh -c echo "deb http://…...
阿里FPGA XCKU3P开箱- 25G 光纤
阿里FPGA XCKU3P开箱 - Hello-FPGA - 博客园 25G 光纤 板子有2个SFP的光纤接口,最大支持25G速率,使用ibert 进行验证,SFP在BANK227的GTY 接口。 ibert 配置如下: 测试 测试符合预期,确认了SFP的具体位置 和 支持的速…...
ArrayList vs LinkedList,HashMap vs TreeMap:如何选择最适合的集合类?
精心整理了最新的面试资料和简历模板,有需要的可以自行获取 点击前往百度网盘获取 点击前往夸克网盘获取 在 Java 开发中,集合类的选择直接影响程序的性能和代码的可维护性。不同的数据结构适用于不同的场景,盲目使用可能导致内存浪费、性能…...
uniapp的h5,打开的时候,标题会一闪而过应用名称,再显示当前页面的标题
问题: 微信小程序,通过webview打开了uniapp创建的h5,但是打开h5时,会先显示h5的应用名称,然后才切换为该页面的标题。 过程: 查过很多资料,有说修改应用名称,有说设置navigationS…...
玩转Docker | 使用Docker搭建Van-Nav导航站
玩转Docker | 使用Docker搭建Van-Nav导航站 前言一、Van-Nav介绍van-nav 简介主要特点二、系统要求环境要求环境检查Docker版本检查检查操作系统版本三、部署Van-Nav服务下载镜像创建容器检查容器状态检查服务端口安全设置四、访问Van-Nav应用访问Van-Nav首页登录后台管理五、添…...
Margin和Padding在WPF和CSS中的不同
CSS和WPF中 margin 与 padding 在方向上的规定基本一致,但在使用场景和一些细节上有所不同。 CSS - 方向规定: margin 和 padding 属性可以分别指定上、右、下、左四个方向的值。例如 margin:10px 20px 30px 40px; 表示上外边距为10px、右外边距为20…...
.NET Core DI(依赖注入)的生命周期及应用场景
在.NET中,依赖注入(DI,Dependency Injection)是一种设计模式,它通过将依赖关系注入到类中,而不是让类自己创建依赖项,来降低类之间的耦合度。这使得代码更加模块化、灵活和易于测试。在.NET中&a…...
新技术学习方法
新技术学习方法 学习新技术的路线需要结合系统性规划与实践验证,以下是基于行业经验和学习科学整理的高效路径框架,适用于编程语言、开发框架、前沿技术等领域: 一、明确学习目标与动机(战略层) 场景化需求分析 明确…...
内网dns权威域名服务器搭建
目录 一、背景 二、dns简介 1、dns服务器类型 1、缓存域名服务器 2、主域名服务器 3、从域名服务器 2、dns解析过程 1、递归查询 2、迭代查询: 3、dns服务器类型 1、根域名服务器 2、顶级域名服务器 顶级域名可分为两类 顶级域名服务器的重要性体现在…...
爱普生SG2520VGN差分晶振5G基站的时钟解决方案
在 5G 通信时代,数据流量呈爆发式增长,5G 基站作为信号的核心中转枢纽,承载着前所未有的数据传输与处理重任。从海量的物联网设备连接,到高速移动用户的数据交互,每一个环节都对基站的性能提出了严苛要求。而精准稳定的…...
Linux中设置文件开机自启
###方法有很多,这里只分享一个systemd的方法 1.创建service文件 在/etc/systemd/system/下创建,自己命名,后缀是.service 创建方式有两种: 进入/etc/systemd/system创建,创建后使用sudo vim编辑使用sudo nano /etc/…...
C# 基类型和派生类型之间的转型
1.什么是基类型和派生类 基类型:父类,所有子类都继承自它。 派生类型:子类,继承了父类的属性和方法,还可以添加自己的新功能。 例子: class Animal { }//基类型 class Dog : Animal { }//派生类型 这…...
AWTK-MVVM 如何让多个View复用一个Model记录+关于app_conf的踩坑
前言 有这么一个业务,主界面点击应用窗口进入声纳显示界面,声纳显示界面再通过按钮进入菜单界面,菜单界面有很多关于该声纳显示界面的设置项,比如量程,增益,时间显示,亮度,对比度等…...
MySQL视图相关
视图基础概念 定义:视图是一条SELECT语句执行后返回的结果集,是对若干基本表的引用,是一张虚表,不存储具体数据。特性:依赖基本表,基本表数据改变时视图数据也随之改变;限定条件下可进行增删改…...
blender 超逼真角色daz 纹理材质 humanpro插件
https://www.youtube.com/KhanhVo-zp9lh/featured https://superhivemarket.com/products/humanpro https://superhivemarket.com/products/humanpro HUMANPRO 插件 - BLENDER HumanPro 是一款专为帮助用户轻松快速地创建高度精细逼真的人体皮肤纹理和复杂皱纹而设计的插件…...
C++简易日志
文章目录 main.cppLog.hLog.cppClassAuxMacro.hSingleton.h main.cpp #include "Log.h"int main() {LogInfo << "main start";int i 1;double d 3.14;LogInfo << "i " << i << ", d " << d;getcha…...
