Verify steps
Description
下载哪种产物、解压到哪里(zip_type / core_unzip),现在只看压缩包大小。OpenWrt 上有两件事没被考虑:
$TMPDIR 在 tmpfs 上,解压出来的内核直接占 RAM,计入 Shmem,不可回收;
- overlayfs 底下的 ubifs/squashfs 透明压缩,裸二进制存进去并不占那么多闪存。
结果是压缩得越狠,运行时占的内存越多。同一个内核(bin/meta/clash-linux-arm64.upx 与 .tar.gz 里的是同一个 aarch64 构建,30277758 字节),三种存法:
| 存法 |
闪存实占 |
不可回收内存 |
.upx |
9.08 MB |
≥ 28.88 MB,且更差,见下 |
.tar.gz 解压到 $TMPDIR |
10.56 MB |
28.88 MB(tmpfs) |
裸二进制放 $BINDIR |
13.09 MB |
0 |
闪存一列在 ubifs 上实测。压缩包压不动(.tar.gz 1.02:1),裸二进制 2.21:1,所以裸二进制只比 .tar.gz 多占 2.5 MB。
.upx 最亏。UPX 的 stub 在 exec 时 memfd_create 把整个程序解压回内存(/proc/PID/maps 里的 /memfd:upx),memfd 本身就是 tmpfs,一样算 Shmem;rodata/data 还从共享文件映射变成了私有匿名页。换成 upx 内核后实测 MemAvailable 少了约 19 MB。
复现
# 改造前:内核解压在 /tmp/ShellCrash/CrashCore
$ grep -E '^(MemAvailable|Shmem):' /proc/meminfo
MemAvailable: 39900 kB
Shmem: 45128 kB
$ grep -E '^Rss' /proc/$(pidof CrashCore)/status
RssAnon: 41856 kB
RssFile: 176 kB
RssShmem: 36876 kB
# 让内核留在 $BINDIR 上执行。借用 core_unzip 对 .upx 只软链不解压的分支,
# 但文件其实是未压缩的裸二进制。
$ /etc/init.d/shellcrash stop
$ gzip -dc /etc/ShellCrash/CrashCore.gz > /etc/ShellCrash/CrashCore.upx
$ chmod +x /etc/ShellCrash/CrashCore.upx
$ rm -f /etc/ShellCrash/CrashCore.gz /tmp/ShellCrash/CrashCore
$ /etc/init.d/shellcrash start
# 改造后
$ grep -E '^(MemAvailable|Shmem):' /proc/meminfo
MemAvailable: 75724 kB
Shmem: 980 kB
$ grep -E '^Rss' /proc/$(pidof CrashCore)/status
RssAnon: 28456 kB
RssFile: 36096 kB
RssShmem: 0 kB
RssShmem 归零,RssFile 接手 —— 代码段和 rodata 变成 file-backed、按需分页、内核可回收。/tmp 占用从 45.1 MB 降到 2.0 MB。
修复方案
不必新增下载格式 —— 照常下载 .tar.gz/.gz(里面本就是裸二进制)。变的是存储策略,由文件系统条件决定:
- 当
$TMPDIR 是 tmpfs(RAM)且 $BINDIR 在透明压缩的 fs(squashfs / ubifs / overlay-over-them)上时:把校验好的裸二进制留在 $BINDIR,$TMPDIR/CrashCore 软链过去,不解压到 tmp、也不保留下载的压缩包。
- 否则维持现状(rom 上留压缩件,启动时解压到 tmp)。
现状对这类设备是双重浪费:rom 上留一份压缩 CrashCore.gz,每次启动又解压整份到 tmpfs 常驻。而 ubifs 本身透明压缩,裸二进制存进去(约 2.2:1)和留 .gz 闪存占用相当,却省下整份 RAM。.raw 只是落盘形态,不是下载格式 —— 下载仍走 .tar.gz/.gz,core_find 的 CrashCore.* glob 配合 core_unzip 的 .raw 分支在启动时重建软链。
已提交 #1305 实现,并在真实 fs 上验证三条路径:压缩 rom 存 raw;重启 core_find 重建软链、运行时 RssShmem 归零;非压缩 rom 回退旧行为。顺带修正了 upx 分支软链目标 $TMPDIR→$BINDIR(与 #1295 同一处悬空 bug)。
环境:ImmortalWrt 25.12,ShellCrash 1.9.5alpha14,aarch64。
Verify steps
.upx软链 bug)Description
下载哪种产物、解压到哪里(
zip_type/core_unzip),现在只看压缩包大小。OpenWrt 上有两件事没被考虑:$TMPDIR在 tmpfs 上,解压出来的内核直接占 RAM,计入Shmem,不可回收;结果是压缩得越狠,运行时占的内存越多。同一个内核(
bin/meta/clash-linux-arm64.upx与.tar.gz里的是同一个 aarch64 构建,30277758 字节),三种存法:.upx.tar.gz解压到$TMPDIR$BINDIR闪存一列在 ubifs 上实测。压缩包压不动(
.tar.gz1.02:1),裸二进制 2.21:1,所以裸二进制只比.tar.gz多占 2.5 MB。.upx最亏。UPX 的 stub 在 exec 时memfd_create把整个程序解压回内存(/proc/PID/maps里的/memfd:upx),memfd 本身就是 tmpfs,一样算Shmem;rodata/data 还从共享文件映射变成了私有匿名页。换成 upx 内核后实测MemAvailable少了约 19 MB。复现
RssShmem归零,RssFile接手 —— 代码段和 rodata 变成 file-backed、按需分页、内核可回收。/tmp占用从 45.1 MB 降到 2.0 MB。修复方案
不必新增下载格式 —— 照常下载
.tar.gz/.gz(里面本就是裸二进制)。变的是存储策略,由文件系统条件决定:$TMPDIR是 tmpfs(RAM)且$BINDIR在透明压缩的 fs(squashfs / ubifs / overlay-over-them)上时:把校验好的裸二进制留在$BINDIR,$TMPDIR/CrashCore软链过去,不解压到 tmp、也不保留下载的压缩包。现状对这类设备是双重浪费:rom 上留一份压缩
CrashCore.gz,每次启动又解压整份到 tmpfs 常驻。而 ubifs 本身透明压缩,裸二进制存进去(约 2.2:1)和留.gz闪存占用相当,却省下整份 RAM。.raw只是落盘形态,不是下载格式 —— 下载仍走.tar.gz/.gz,core_find的CrashCore.*glob 配合core_unzip的.raw分支在启动时重建软链。已提交 #1305 实现,并在真实 fs 上验证三条路径:压缩 rom 存 raw;重启
core_find重建软链、运行时RssShmem归零;非压缩 rom 回退旧行为。顺带修正了 upx 分支软链目标$TMPDIR→$BINDIR(与 #1295 同一处悬空 bug)。环境:ImmortalWrt 25.12,ShellCrash 1.9.5alpha14,aarch64。