Rust
二进制文件大小优化,在优化二进制文件过程中,编译工夫会减少,然而个别编译时候的优化会放慢程序执行速度
初始化我的项目
在 Ubuntu22
下面进行试验
创立我的项目
$ cargo new demo
批改 Cargo.toml
如下,须要退出一点罕用的库
[dependencies]
tokio = {version = "1", features = ["full"]}
tracing = "0.1"
tracing-subscriber = "0.3"
批改 main.rs
如下
#[tokio::main]
async fn main() {tracing_subscriber::fmt::init();
loop {tokio::time::sleep(std::time::Duration::from_secs(1)).await;
tracing::info!("Hello, world!");
}
}
debug
和 release
的大小比照
编译
$ cargo build
$ cargo build -r
查看大小
$ ll target/*
target/debug:
总计 28M
-rwxrwxr-x 2 gong gong 28M 四月 25 15:47 demo
...
target/release:
总计 5.0M
-rwxrwxr-x 2 gong gong 5.0M 四月 25 15:46 demo
....
可见 release
版本二进制大概是 debug
版本的 17%
,后续所有二进制优化采纳release 5M
大小为基准,每次优化都只改变一个配置项作为比照
优化符号信息symbols
在 Linux
和macOS
上,默认状况下,符号信息蕴含在编译的 .elf
文件中,正确执行二进制文件不须要此信息
配置Cross.toml
[profile.release]
strip = true
编译之后 demo
二进制变为887k
,约为之前的17%
,成果好
这个配置项在我的项目比拟大的时候,比方最终二进制是 100M
优化成果就不怎么显著了,个别符号信息是会减小几 M 大小,存在一个下限
配置优化level
默认的 release opt-level
是 3,debug opt-level
是 0
[profile.release]
opt-level = "z"
优化后 demo
变为 5.1M
了,二进制反而变大,很多文档都提到要配置这个优化项,然而素来没发现有什么成果
详情参考官网文档
https://doc.rust-lang.org/cargo/reference/profiles.html
启用链接时优化
默认状况下,Cargo
批示编译单元独自编译和优化,LTO
批示链接器在链接阶段进行优化,例如,这能够删除无用代码,有些代码段不会被调用到,并缩小二进制大小
默认 release
是没有开启这个配置,开启这个配置后如果我的项目比拟大,则会大幅度减少编译工夫,我的项目依赖越多,代码总量越多,优化成果越显著
[profile.release]
lto = true
编译后二进制变为2.6M
,约为之前的52%
,成果好
缩小并行代码生成单元
Cargo
为公布版本指定了 16 个并行代码单元,这改善了编译工夫,但障碍了一些优化,如果配置为 1,就能够最大水平防止并行代码单元中的障碍优化
[profile.release]
codegen-units = 1
编译后文件大小为4.8M
,约为之前的96%
,成果不怎么显著
配置程序 panic
时候的行为
当 Rust
代码遇到必须调用 panic!()
的状况时,它会开展堆栈并生成有用的回溯,开展代码须要额定的二进制,能够调整 Rust
立刻停止程序而不是开展栈信息,这样就不须要额定的开展代码
[profile.release]
panic = "abort"
编译后程序大小为 4.7M
,约为之前的97.5%
,这样配置的话程序如果报错就看不到什么中央panic
了,会比拟影响线上环境体验,不举荐应用
大杀器UPX
upx
是一个二进制压缩工具,反对各类二进制可执行文件的压缩,rust/golang/c.....
,在大部分状况下能够把二进制执行文件压缩到原来的 30%
左右,压缩后的文件能够间接由零碎执行,反对多零碎和平台
我的项目地址
装置的时候尽量去官网我的项目的 release
获取到最新的 release
,外面蕴含一个upx
可执行文件用于压缩二进制程序
https://github.com/upx/upx
upx
反对不同的压缩级别1-9
,最高压缩级别是9
个别执行 upx -9 文件
即可
$ upx -9 target/release/demo
Ultimate Packer for eXecutables
Copyright (C) 1996 - 2023
UPX 4.0.2 Markus Oberhumer, Laszlo Molnar & John Reiser Jan 30th 2023
File size Ratio Format Name
-------------------- ------ ----------- -----------
5178056 -> 1173024 22.65% linux/amd64 demo
Packed 1 file.
之后查看二进制可执行文件变为了1.2M
,约为原来的22.6%
linux
下面应用 strings
查看二进制文件
查看压缩前的可执行文件内容
$ strings target/release/demo |head -n 10
/lib64/ld-linux-x86-64.so.2
_ITM_deregisterTMCloneTable
__gmon_start__
_ITM_registerTMCloneTable
_Unwind_Resume
_Unwind_Backtrace
_Unwind_GetLanguageSpecificData
_Unwind_GetIPInfo
_Unwind_GetDataRelBase
_Unwind_GetRegionStart
查看压缩后的内容,能够看到 UPX
把结尾的信息改写了
$ strings target/release/demo |head -n 10
1tUPX!
m@/H
(O0OS
tdPo
/lib64
nux-x86-
.so.
_ITM_deregist
CloneTable
__gm_.art
原理
采纳二进制程序加壳技术,UPX
将程序压缩,并在头部退出解压的程序,加壳过的程序能够间接运行,然而不能查看源代码,要通过脱壳才能够查看源代码
加壳与解压
- 在文件头里加了一段指令,通知 CPU,怎么能力解压本人(在解压时候执行)
- 利用非凡的算法,对
EXE
、DLL
,其余二进制文件里的资源进行压缩,相似zip
的成果 - 压缩之后的文件,能够独立运行,给可执行的文件加上个外衣
- 加壳工具解压过程齐全荫蔽,都在内存中实现,用户执行的只是这个外壳程序
- 执行时候,壳就会把原来的程序在内存中解开,解开后,当前的就交给真正的程序
长处
UPX
能够压缩各种类型的可执行文件,压缩效率十分可观- 压缩后的文件能够间接由操作系统执行
- 压缩过程不会批改源文件,也就意味着解压后间接能够失去原始文件
- 不会产生额定的动静库调用
- 没有运行时性能损失
- 反跟踪、被人跟踪调试、避免程序被他人动态剖析,爱护你程序数据的完整性,避免被程序修改和被窥视底细
毛病
- 运行的程序不会共享数据段(汇编),所以多实例运行的程序不适宜压缩
- 应用
ldd
和size
命令无奈获取到程序的无效信息 - 关上时耗费更多的
CPU
资源(执行的时候会应用解压算法对压缩后的可执行文件进行解压运算) - 在运行时占用更多的内存(次要是多了几兆
UPX
解压程序)
总结
很多优化形式个别都是压缩成果不怎么显著,然而会减少编译耗时或者影响程序应用体验
所以采纳优化形式如下
- 启用链接时优化
- 除去不必要的
Symbols
- 采纳
upx
进一步压缩
配置 Cargo.toml
为如下
[profile.release]
strip = true
lto = true
参考浏览
Minimizing Rust Binary Size
应用 UPX
压缩可执行文件
How They Work, Featuring UPX