
开发工具移动开发【免费下载链接】redexA bytecode optimizer for Android apps项目地址https://gitcode.com/gh_mirrors/re/redex点击查看免费下载本版本发布说明website/blog/2025-09-18-release.md聚焦于 Redex 字节码优化器的一批内部改进其中最值得关注的是在 Constant Propagation常量传播体系中引入的 Kotlin 默认参数优化以及通过 inliner 新增max_reduced_size选项来削减 Redex 自身内存占用。读完本文你将掌握这一版本在 Kotlin 默认参数合成方法上的优化原理与验证方式理解 inliner 内存削减选项的底层实现与配置方法并能从确定性容器迁移中看到 Redex 对可复现构建的坚持。版本概览一次以优化与内部改进为主的发布v2025.09.18 发布说明全文非常精炼共包含两部分内容Optimizations优化Kotlin 默认参数优化被引入 Constant Propagation 体系中。Other improvements其他改进三项内部工程改进包括新无序容器类型的更多采用、通过 inliner 新选项max_reduced_size降低内存占用、以及为模糊测试fuzzing改进 JarLoader。虽然没有引入新的 Pass 名称或命令行开关但每一项背后都有对应的源码实现与集成测试支撑下面逐一展开。Kotlin 默认参数优化从合成方法中清除冗余默认值背景Kotlin 默认参数在字节码中的形态当 Kotlin 代码中的函数带有默认参数时编译器会生成一个名为方法名$default的合成synthetic静态方法。以仓库中的集成测试用例 test/integ/KotlinDefaultArgs.kt 为例class KotlinDefaultArgs { private fun greet(name: String Guest, greeting: String Hello) { print($greeting, $name!) } fun main() { // Never called greet with the default greeting greet(greeting Hi) // Uses default name: Hi, Guest! greet(Bob, Welcome) // Uses provided arguments: Welcome, Bob! } }编译后会产生LKotlinDefaultArgs;.greet$default:(LKotlinDefaultArgs;Ljava/lang/String;Ljava/lang/String;ILjava/lang/Object;)V这样的合成方法——前两个参数对应真实的name、greeting其后的I参数是一个掩码mask位集合用于指示调用方省略了哪些默认参数最后的Ljava/lang/Object;是 Kotlin 生成的占位参数。合成方法内部用掩码与and-*位运算指令判断哪些参数被省略并为被省略的参数填充默认值。opt/print-kotlin-stats/PrintKotlinStats.cpp中的is_kotlin_default_arg_method正是按“方法名以$default结尾且参数个数大于 2含末尾的掩码与占位参数”这一特征来识别这类方法的。优化原理常量传播发现“永远不会用到的默认值”在未优化的代码中greet$default合成方法里会无条件保留Guest、Hello这两个字符串默认值以及对应的掩码位运算指令。而本次版本引入的优化是在 Constant Propagation进程间常量传播即InterproceduralConstantPropagationPass阶段分析所有调用点实际传入的掩码常量如果某位掩码在所有实际调用中都恒为固定值那么对应的默认分支就是死代码默认值常量可以被安全删除。以测试用例 test/integ/KotlinDefaultArgsTest.cpp 的两个用例来看UnoptimizedGreetHasHelloAnd优化前合成方法的字节码中必然包含默认字符串Hello与and-*掩码运算指令OptimizedGreetDoesNotHaveHelloAnd只运行InterproceduralConstantPropagationPass这一个 Pass 之后由于main中两次调用greet均显式提供了greetingHi与Welcomegreeting的默认值Hello以及相关的掩码判断指令会被清除而name参数至少有一次调用使用了默认值因此Guest会被保留。测试断言清晰验证了这一行为见 test/integ/KotlinDefaultArgsTest.cppEXPECT_THAT(assembler::to_string(code_syn_default_arg), HasSubstr(Guest)) Default arg \name\ is used, but the synthetic default method has dropped its default value \Guest\; EXPECT_THAT(assembler::to_string(code_syn_default_arg), Not(HasSubstr(Hello))) Default arg \greeting\ is never used, but the synthetic default method still contains its default value \Hello\;源码侧的实现位置该优化落在常量传播体系内。进程间常量传播的入口与核心分析代码位于service/constant-propagation/IPConstantPropagation.cppPass 入口与整体流程service/constant-propagation/ConstantPropagationTransform.cpp基于分析结果改写指令、删除冗余指令service/constant-propagation/ConstantPropagationAnalysis.cpp指令语义分析确定各寄存器与参数在调用点的常量取值。这一优化与此前版本的 Kotlin null-check 消除见 service/constant-propagation/ConstantPropagationTransform.cppeliminate_redundant_null_check会识别 Kotlin null-check 内在函数并在参数已确定为非空时删除调用同属常量传播的价值取向让合成代码中因“调用点信息”而变得多余的部分消失最终缩减 dex 体积并减少运行时的掩码判断开销。如果你用-P参数运行该 Pass可以从统计指标如 service/constant-propagation/ConstantPropagationPass.h 中定义、IPConstantPropagation.cpp中上报的added_param_const、null_checks等计数观察优化覆盖情况opt/print-kotlin-stats/PrintKotlinStats.cpp还提供了kotlin_default_arg_1_param、kotlin_default_arg_2_params、kotlin_hot_default_arg_1_param等按默认参数个数与调用热度结合 method profiles分类的统计口径。内存削减inliner 新增 max_reduced_size 选项该选项要解决的问题Redex 的 inliner 在评估“是否值得内联某个调用点”时会基于常量传播结果生成一份“精简后的被调方法代码”reduced code用于更精确地估算内联成本。问题在于如果这类精简代码块不加限制地全部保留在内存中大量大方法的中间表示会显著推高 Redex 自身的内存峰值。max_reduced_size正是为这个场景设计的阈值为特定调用点保留的精简代码的最大尺寸。其默认值定义在 libredex/InlinerConfig.h// Maximum size of reduced code to keep for specific call-site. It just takes // too much memory to retain individual larger reduced code. const size_t MAX_REDUCED_SIZE 100;配置结构体中的字段声明位于 libredex/InlinerConfig.h// max_reduced_size is maximum size of reduced code to keep for particular // callsite. size_t max_reduced_size{MAX_REDUCED_SIZE};源码中的判定逻辑在 service/method-inliner/Inliner.cpp 的MultiMethodInliner::get_call_site_inlined_cost中计算出调用点内联成本后会执行如下判定if (inlined_cost.insn_size std::min(fully_inlined_cost-insn_size, m_config.max_reduced_size)) { make_partial(callee, inlined_cost); }即当某调用点精简代码的指令规模不小于min(完全内联尺寸, max_reduced_size)时调用make_partial丢弃该精简代码reduced_code.reset()见 service/method-inliner/Inliner.cpp从而及时释放这一部分内存在partial_hot_hot_inline开启且目标方法确实为热点方法时还会先截取热前缀的局部代码再释放。从配置绑定看max_reduced_size通过inliner配置块注册到全局配置系统libredex/GlobalConfig.cpp 与register_asInlinerConfig(inliner)。因此在配置文件中它可以这样使用{ inliner: { max_reduced_size: 100, max_cost_for_constant_propagation: 5000, max_partially_inlined_code_units: 10 } }说明max_reduced_size按调用点保留精简代码的尺寸上限调小可进一步压低内存峰值但可能损失内联成本估算的精确度max_cost_for_constant_propagation决定多大方法才值得用常量传播来辅助估算内联成本默认 5000见 libredex/InlinerConfig.h 及其同文件中MAX_COST_FOR_CONSTANT_PROPAGATION的定义max_partially_inlined_code_units部分内联时保留的热前缀代码单元上限默认 10。更广泛地采用新的无序容器类型可复现构建背景下的容器抉择Redex 必须产出 bit-for-bit 可复现的 APK相同的输入必须始终产出相同的输出否则构建缓存与可验证发布都会失效。而直接遍历std::unordered_map/std::unordered_set的偶然顺序incidental order恰恰会悄然破坏这一点——同一输入在不同运行之间可能产出不同结果表现为偶发构建失败或缓存未命中。为此仓库在 libredex/DeterministicContainers.h 中提供了UnorderedSet/UnorderedMap/UnorderedBag等包装容器。文档注释中的最佳实践明确指出libredex/DeterministicContainers.h用UnorderedSet/UnorderedMap替代std::unordered_set/std::unordered_map元素顺序不确定的std::vector应改用UnorderedBag遍历无序容器时如果确定迭代顺序不影响最终结果的确定性用UnorderedIterable(...)包装显式声明需要排序时使用unordered_to_ordered/unordered_to_ordered_keys辅助函数。与 CI 配合的防回归机制更关键的是这些包装类型配合编译开关REDEX_PERTURB_UNORDERED使用libredex/DeterministicContainers.h该开关默认关闭零成本、字节一致在 CI/调试构建下打开时会故意按容器、按运行扰乱遍历顺序使任何依然依赖偶然顺序的代码产生分歧输出从而被 Redex 的可复现性信号捕获在代码合入前就暴露问题。本版本“更多采用新无序容器类型”即表示inliner、常量传播等 Pass 中的更多数据结构已迁移到这类确定性容器上进一步收紧了可复现构建的防线。在代码中可直接看到此类迁移的痕迹例如 libredex/AnalysisUsage.cpp 与 libredex/InlinerConfig.hno_inline_annos、force_inline_annos均为UnorderedSetconst DexType*。JarLoader 的 fuzzing 改进本次发布还提到 JarLoader 针对模糊测试fuzzing的改进。JarLoader 是 Redex 读取 Java 类文件JAR/JDK 类库的加载器相关实现位于 libredex/JarLoader.cpp 与 libredex/JarLoader.h。由于 fuzzing 会不断向解析器投喂畸形、截断或非法的输入这类改进通常集中在对异常输入做更健壮的错误处理、避免崩溃与未定义行为、以及在解析失败时给出可诊断的错误信息。发布说明未给出具体细节从源码结构与发布文本可以推断这是一项提升 Redex 在对抗性输入下健壮性的工程化改进。如何自行验证这一版本的行为仓库提供了可复现的集成测试来验证上述优化建议按如下路径自行验证查看测试输入阅读 test/integ/KotlinDefaultArgs.kt了解默认参数函数的构造运行集成测试构建后运行KotlinDefaultArgsTest位于 test/integ/KotlinDefaultArgsTest.cpp其测试目标KotlinDefaultArgsIntegrationTest在 test/integ/Makefile.am 中定义该测试仅执行InterproceduralConstantPropagationPass一个 Pass并断言合成方法中默认字符串与掩码指令的存留情况观察统计如需观察 Kotlin 默认参数的规模与热度分布可启用print-kotlin-statsPassopt/print-kotlin-stats/PrintKotlinStats.cpp它会输出kotlin_default_arg_*、kotlin_hot_default_arg_*等指标调整 inliner 配置在-P传入的配置 JSON 中按上文示例设置inliner.max_reduced_size对比 Redex 运行峰值内存与产物字节码。小结v2025.09.18 是一个“小而精”的发布核心亮点是把 Kotlin 默认参数的冗余默认值清除下沉到常量传播阶段用真实调用点信息裁剪合成方法同时通过max_reduced_size为 inliner 的内存占用设置明确边界通过确定性容器迁移巩固可复现构建的根基并为 JarLoader 的模糊测试健壮性做了铺垫。对于在 Android 构建管线中集成 Redex 的团队这一版本提示了一个值得养成的习惯为$default合成方法写测试断言、用print-kotlin-stats度量、并在 inliner 配置中显式声明内存与精度的取舍。赞分享开发工具移动开发【免费下载链接】redexA bytecode optimizer for Android apps项目地址https://gitcode.com/gh_mirrors/re/redex点击查看免费下载相关推荐Kubo v0.36 版本深度解析HTTP Retrieval 默认启用、Bitswap 广播削减与连接管理优化Kubo v0.36 版本深度解析HTTP Retrieval 默认启用、Bitswap 广播削减与连接管理优化 本文基于仓库内 docs/changelog网络存储后端Redex v2026.04.30 版本解析注解清扫、跨 Dex 内联放宽与新指针容器优化Redex v2026.04.30 版本解析注解清扫、跨 Dex 内联放宽与新指针容器优化 本指南系统讲解 RedexAndroid 应用字节码优化器v2开发工具移动开发Numba 0.58.1 维护版本解析NumPy 1.26 兼容支持与内联闭包默认参数修复Numba 0.58.1 维护版本解析NumPy 1.26 兼容支持与内联闭包默认参数修复 本文围绕 Numba 0.58.12023 10 17 发布的维编译器高性能计算上一篇use-persisted-state核心原理深度解析从localStorage到跨标签通信的终极指南下一篇yaml-cpp 版本发布完整指南从开发到稳定版的7个关键步骤 创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考