跳到主要内容

DHAO 文件

dhao文件是DHE技术的核心概念。dhao文件中包含了离线计算好的最新的热更新dll中变化的类型和函数的信息,运行时直接根据dhao文件中信息决定执行某个热更新函数时,应该使用最新的解释版本还是直接调用原始的AOT函数。 离线计算好的dhao文件对于DHE技术极为关键,如果没有dhao文件,需要额外携带原始AOT dll,并且计算函数变化的代价极其高昂。

通过对比最新的热更新dll与打包时生成的AOT dll,离线计算出变化的类型与函数,保存成dhao文件。因此DHE机制要正常工作,必须依赖于dhao文件的正确性,而dhao文件的正确性 则依赖精确提供最新的热更新dll和打包时生成的AOT dll。

HybridCLR.Editor.DHE.BuildUtils提供了多个生成dhao文件相关的函数。

函数名描述
GenerateDHAODatas生成热更新包(即有代码发生改变时)的dhao文件
EncryptDllAndGenerateDHAODatas当开启初级代码加固时,生成热更新包(即有代码发生改变时)加密后的dll和dhao文件

标记变化的函数信息

目前已经可以自动通过对比最新的热更新dll和打包时生成的aot dll,计算出变化的函数,绝大多数情况下不需要手动操作。但事实上并不存在完美的能够判断逻辑等价性的代码, 工具只是简单地一一对比IL来判断等价性。有时候可能发生函数是等价的但IL发生变化的情况(如调换了两行不相关代码的顺序),则会被判定为函数发生变换而切到解释执行。 如果发生了这种情况,并且对该函数有极其严苛的性能要求,开发者可以手动使用UnchangedAttribute特性标注函数的变化性。 [Unchanged][Unchanged(true)]表示未变化,[Unchanged(false)]表示变化,未标记特性则由工具自动计算。

错误地将未变化函数标记为已变化,不会影响运行的正确性,只会影响性能。就算将所有热更新函数都标记为变化,也能正常运行。但错误地将变化函数标记为未变化,不仅会导致运行逻辑出错, 严重情况下还会导致崩溃!

警告

除非特殊情况以及你是有经验的专家,不要手动标记。因为编译器经常生成一些隐藏类或字段,这些类名并不是稳定的。表面看起来一样的C#代码,实际生成的代码未必一样,强行标注为[Unchanged]会导致不正确的运行逻辑,甚至崩溃。

合并dhao文件

基于相同或者相似源码发布的游戏包,它们的原始dhe程序集在不同平台之间仅有微小区分,热更新时生成的dhao文件也只有微小区别。 导致需要为每个平台都计算单独的dhao文件(即使是相同平台,由于代码编译的不稳定性,生成的原始dll也可能有微小区别),这导致维护dhao工作变得复杂易错。当多个新旧游戏包同时存在时,这个问题尤为严重。 可以考虑将同一个dhe程序集对应的多个平台的dhao文件合并,不影响运行正确性的同时对性能的影响也很小。

我们提供了HybridCLR.Editor.DHE.BuildUtil::MergeDHAOFiles函数实现合并dhao文件目标。

注意,带校验的工作流无法使用合并dhao文件的方式,因为带校验的工作流会检查原始dll的md5码,这个肯定是不匹配的。

注意事项

外部dll引发的计算dhao的结果有巨量差异

如果有外部dll被标记为DHE程序集,由于外部dll打包时会被裁剪,而计算dhao文件时,取的是原始的外部dll,导致产生巨量的差异,这不是所期望的。解决办法有几个:

  1. 在link.xml里<assembly fullname="YourExternDll" preserve="all"/> 完全保留外部dll
  2. 不用最新的热更新dll去计算差异,而是使用最新代码重新打包时生成的aot dll去计算差异