Release 产物 1.74MB → 796KB(去掉 <filesystem> 与 zlib)+ .mat 加载进度不再停住
一、体积膨胀的真因(用 -Wl,-Map 逐对象/逐节对比上一提交定位,只有两个) 1) <filesystem>(致命,约 +900KB):MatH5::Open 用 std::filesystem::file_size 取文件大小, MinGW 的 libstdc++ 因此链入 fs_path/fs_dir/fs_ops/c++locale/codecvt/collate_members/ cow-wstring-inst/cxx11-wlocale-inst/fstream-inst/cp-demangle 整套 locale/iostream 机器 (归档成员 415→538);还把 64KB 静态表从 .bss 挤成 .data(1.8KB→73.8KB)。 修法:改用 _wfopen_s + _fseeki64/_ftelli64 取大小。 2) -lz(约 46KB):只需要"解开 HDF5 分块"。修法:MatH5 内置紧凑 inflate (RFC1950/1951:固定/动态 Huffman、存储块、长度-距离回抄),Makefile 与探针脚本移除 -lz。 顺带把 UploadHaloLayer 里 64KB 的预乘 alpha 查表换成 (v*a+128)*257>>16(无除法、无表)。 二、压到 800KB 以下的两项无损措施 1) 图标资源无损重编码:ico 里 64/48/32/16 四帧原为未压缩 32bpp DIB(合计 32KB), 用自写工具(GDI+ 编码)改为 PNG 帧(ICO 的 PNG 条目 Vista+ 全支持,本文件本就有 256 PNG 帧): 43,334 → 17,404 字节。像素逐点校验:差异 ≤85 像素、最大分量差 ≤3(编码取整),肉眼不可辨; 并从**真实产物** LoadImageW 逐尺寸(16/32/48/64)验证可加载。 2) RELEASE_OPT 由 -Os 改为 -Oz(省约 6KB);实测动画帧 p50 7.73ms(-Os) vs 7.77ms(-Oz), 无可辨识差异。 放弃的手段:-ffunction-sections/-fdata-sections + --gc-sections(反而 +9KB)、LTO(工具链 ICE)、 -fno-asynchronous-unwind-tables(链接失败)、-fno-exceptions(会破坏 catch (bad_alloc))。 结果:Build/Release/Target.exe = 795,648 字节。 三、.mat 加载进度不更新(已加载大小 / 总大小 / 百分比都停在 0) 真因:LoadMatSourceGroups 只在结束时回调一次 ratio=1.0,且从不设置 hasBytes; 读 42MB 文件与解码 19 个样本流(解压+拷贝,占大头)期间进度恒为 0。 修法: - MatHdf5::Open 新增 OpenProgress(bytesRead,totalBytes),按 4MB 分块读取并回报; - MatLoader 用 ProgressReporter 把进度拆成 0.00–0.55 读文件(hasBytes=true)与 0.55–0.98 解码样本流(每解完一个流推进 done/total),末段 1.0; - 取消与出错分开:取消时清空 error,不弹错误框。 实测:回调 29 次、字节数变化 11 次、比例单调、终值 1.000、bytes=42,386,344/42,386,344 (= 文件大小);Application 侧断言 m_loadingBytesRead == m_loadingTotalBytes == 文件大小。 四、验证(全部离屏,不占用鼠标/键盘/屏幕) - matcheck 21/21(新增进度断言)、matui 15/15(新增图标 + 加载字节断言); - 回归 verify 49/49、panelanim 158/158、gridanim 93/93、hoverdrag 20/20、lanescroll 23/23、 datacheck 69/69、edgecheck 46/46、errcheck 19/19、halocheck 16/16、panflash 19/19、 panelstutter 8/8、stress 6/6; - make release / make debug 零警告。 文档:Documents/agent_mem.md 追加本轮小节(含 5 条新规则:MinGW 下 <filesystem> 是体积炸弹、 链一整条库前先算账、膨胀要看节表而非 .o 大小、图标可无损重编码并用产物校验、 长解析必须按阶段回报进度且 hasBytes 只在有字节时置真)。
This commit is contained in:
1 parent
5b24dacee0
commit
f44f8021e3
8 files changed
+623
-46
No files matched your search
@@ -6272,3 +6272,87 @@ else if (panelOnly) { /* 只回送“本帧重绘过的区域并集” */ }
|
||||
否则消息多、需要续块的对象会读到块外垃圾,字段全部解析失败。
|
||||
4. MATLAB 写出的**分块维度可能与数据空间维度维数不同**(1 维数据集的分块是 `[N,1]`),
|
||||
按"右侧补 1"对齐即可解码。
|
||||
|
||||
---
|
||||
|
||||
## 本轮(2026-10-19):Release 产物 1.74MB → 796KB(只用 2 个真实原因)+ `.mat` 加载进度
|
||||
|
||||
用户报告:① 只加了一个格式支持,Release 二进制却从 ~787KB 涨到 **1.74MB**,要求压回 **< 800KB**;
|
||||
② 加载 `.mat` 时遮罩层的「已加载大小 / 总大小 / 百分比」都不更新,界面只是原地等待。
|
||||
|
||||
### A. ① 体积膨胀的真因只有两个(用 `-Wl,-Map` 逐对象/逐节对比定位)
|
||||
|
||||
对照构建上一提交(`git worktree` + `TARGET_FILE_NAME=TargetOld`)逐节比较 `.text/.data/.rdata/...`:
|
||||
|
||||
1. **`<filesystem>`(致命,+~900KB)**:`MatH5::Open` 为了取文件大小用了
|
||||
`std::filesystem::file_size`。MinGW 的 libstdc++ 会因此链入
|
||||
**`fs_path.o` / `fs_dir.o` / `fs_ops.o` / `c++locale.o` / `codecvt.o` / `collate_members*` /
|
||||
`cow-wstring-inst.o` / `cxx11-wlocale-inst.o` / `fstream-inst.o` / `cp-demangle.o`** 等
|
||||
整套 locale/iostream 机器 —— 成员数 415 → 538,`.text` 615KB → 654KB,且把
|
||||
`.bss` 里 64KB 的静态表挤成 `.data`(`.data` 从 1.8KB 涨到 73.8KB)。
|
||||
修法:改用 `_wfopen_s` + `_fseeki64/_ftelli64` 取大小(零依赖)。
|
||||
2. **`-lz`(~46KB)**:只需要「解开 HDF5 分块」这一功能,不值得链整个 zlib。
|
||||
修法:`MatH5.cpp` 内置一份紧凑 inflate(RFC1950/1951,含固定/动态 Huffman、
|
||||
存储块、长度-距离回抄),同时把 `-lz` 从 Makefile 与探针脚本移除。
|
||||
|
||||
顺带修掉一处**体积隐患**:`UploadHaloLayer` 里 64KB 的预乘 alpha 查表被换成
|
||||
`(v*a+128)*257>>16` 的乘法-移位(无除法、无表)。⚠️ 若将来开 `-fdata-sections`,
|
||||
函数内静态数组会被放进 `.data$_ZZ...`(**实测凭空 +72KB 文件体积**),这条也一并避开了。
|
||||
|
||||
### B. 剩下 ~40KB 的正当成本与最终压缩手段
|
||||
|
||||
去掉上面两项后仍是 825,856(旧版 786,944,+38.9KB = MatH5 15.4KB + MatLoader 12.5KB +
|
||||
对齐/导入表,属"新增一个格式解析器"的正常成本)。要压到 <800KB,采用两项**不改变行为与观感**的措施:
|
||||
|
||||
1. **图标资源无损重编码**:`Resources/JustDataInspector.ico` 里 64/48/32/16 四帧原本是
|
||||
未压缩的 32bpp DIB(合计 32KB),改用 GDI+ 重编码为 PNG 帧(ICO 的 PNG 条目 Vista+
|
||||
全支持,本文件本身就有 256 PNG 帧):**43,334 → 17,404 字节**。
|
||||
像素逐点校验:差异像素 ≤85 个、最大分量差 ≤3(GDI+ 编码取整),肉眼不可辨;
|
||||
`matui` 探针从**真实产物**里 `LoadImageW` 逐一取 16/32/48/64 帧,全部 ok。
|
||||
2. **`RELEASE_OPT` 由 `-Os` 改为 `-Oz`**(省 ~6KB)。实测动画帧 p50 7.73ms(-Os) vs
|
||||
7.77ms(-Oz),无可辨识差异(本项目热点全在 GDI/GDI+ 绘制)。
|
||||
|
||||
⚠️ 试过并**放弃**的手段:`-ffunction-sections -fdata-sections + -Wl,--gc-sections` 反而 +9KB
|
||||
(分节后每函数 16 字节对齐 + 静态量落 `.data`);LTO 在该工具链上 **ICE** 崩溃;
|
||||
`-fno-asynchronous-unwind-tables` 链接失败;`-fno-exceptions` 会破坏 `DataModel` 的
|
||||
`catch (std::bad_alloc)`。
|
||||
|
||||
最终:**`Build/Release/Target.exe` = 795,648 字节**(< 800KB,约 4.4KB 余量)。
|
||||
|
||||
### C. ② `.mat` 加载进度不更新
|
||||
|
||||
真因:`LoadMatSourceGroups` 只在**结束时**回调一次 `ratio=1.0` 且从不设置 `hasBytes`;
|
||||
读文件(42MB)与解码 19 个样本流(解压 + 拷贝,占大头)期间进度恒为 0 ⇒ 遮罩层
|
||||
一直显示 0.00%、总大小未知。
|
||||
|
||||
修法(`MatH5` + `MatLoader`):
|
||||
- `MatHdf5::Open` 新增 `OpenProgress(bytesRead,totalBytes)`,**按 4MB 分块读入并回报**,
|
||||
读完即得到"已加载 = 总大小";
|
||||
- `MatLoader` 用 `ProgressReporter` 把进度拆成 `0.00–0.55 读文件`(`hasBytes=true`)
|
||||
与 `0.55–0.98 解码样本流`(每解完一个流推进 `done/total`),末段 1.0;
|
||||
- 取消(回调返回 false)与出错分开处理:取消时清空 `error`,不弹错误框。
|
||||
|
||||
实测(`matcheck`):回调 **29 次**、其中字节数变化 **11 次**、比例单调、终值 1.000、
|
||||
`bytes=42,386,344/42,386,344`(= 文件大小);`matui` 进一步断言
|
||||
`Application` 的 `m_loadingBytesRead == m_loadingTotalBytes == 文件大小`(遮罩层拿到的值)。
|
||||
|
||||
### D. 验证(全部离屏,不占用鼠标/键盘/屏幕)
|
||||
|
||||
- `matcheck` **21/21**(新增进度断言)、`matui` **15/15**(新增图标 + 加载字节断言);
|
||||
- 回归:`verify` 49/49、`panelanim` 158/158、`gridanim` 93/93、`hoverdrag` 20/20、
|
||||
`lanescroll` 23/23、`datacheck` 69/69、`edgecheck` 46/46、`errcheck` 19/19、
|
||||
`halocheck` 16/16、`panflash` 19/19、`panelstutter` 8/8、`stress` 6/6;
|
||||
- `make release` / `make debug` 零警告;`Build/Release/Target.exe` 795,648 字节。
|
||||
|
||||
### E. 教训(新增规则)
|
||||
|
||||
1. **MinGW 下 `#include <filesystem>` 是体积炸弹**(连带 locale/iostream/demangle 整套,
|
||||
+0.9MB);只需要"取文件大小"时用 `_wfopen_s + _fseeki64`。
|
||||
2. **为一个功能链一整条库前先算账**:`-lz` 46KB vs 自带 inflate 3~4KB;
|
||||
能用几十行自实现的就不要链。
|
||||
3. **判断二进制膨胀要看节表**(`objdump -h` + `-Wl,-Map` 逐对象求和),
|
||||
只看 `.o` 大小会被"归档成员/对齐/`.data` 里的静态表"骗过去。
|
||||
4. **图标资源可以无损重编码**(DIB 帧 → PNG 帧),同一份像素省 60% 体积;
|
||||
用探针从**真实产物** `LoadImageW` 逐尺寸校验,而不是只看文件能编译。
|
||||
5. **任何"长时间解析"都要按阶段回报进度**(读字节 + 每个解码单元),
|
||||
且 `hasBytes` 只在真正有字节可报的阶段置真,否则遮罩层会停在 0%。
|
||||
Reference in new issue
Block a user