Skip to content

Commit

Permalink
[fix] 修复文档错误
Browse files Browse the repository at this point in the history
  • Loading branch information
pirunxi committed Jul 20, 2024
1 parent afa2449 commit 957d223
Show file tree
Hide file tree
Showing 2 changed files with 72 additions and 0 deletions.
37 changes: 37 additions & 0 deletions docs/business/reload/hotreloadassembly.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
# 热重载技术

热重载技术用于完全卸载或者重新加载一个assembly,适用于小游戏合集类型的游戏。该方案只提供**商业化版本**

## 支持的特性

- 支持卸载assembly,卸载100%的assembly所占用的内存
- 支持重新加载assembly,代码可以任意变化甚至完全不同(MonoBehaviour和Scriptable有一定的限制)
- 支持**限定热更新assembly中能访问的函数的集合**,适合UGC游戏中创建沙盒环境,避免恶意玩家代码造成破坏。

## 不支持特性及特殊要求

- 要求业务代码不会再使用被卸载的Assembly中的对象或者函数,并且退出所有在执行的旧逻辑
- 不能直接卸载被依赖的Assembly,必须按照逆依赖顺序先卸载依赖者,再卸载被依赖者。例如A.dll依赖B.dll,则需要先卸载A.dll,再卸载B.dll
- MonoBehaviour和ScriptableObject相关
- 要求重载的MonoBehaviour中的事件或消息函数如Awake、OnEable之类不发生增删(但函数体可以变化)
- 要求重载后在旧Assembly中存在同名脚本类的序列化字段名不发生变化(类型可以变)
- 如果字段类型为可卸载程序集中的自定义类型A(class或struct或enum),必须给它加上`[Serializable]`特性
- 不支持字段类型为`List<A>`其中A为可卸载的程序集中的类型,请替换为`A[]`
- 不能继承泛型类型,例如`class MyScript : CommonScript<int>`
- 一些会缓存反射信息的库(这种行为在序列化相关的库中最为普遍,如LitJson),在热重载后需要清理掉缓存的反射信息
- 不支持析构函数,~XXX()。也不允许实例化泛型参数带本程序集类型的带析构函数的泛型类
- 与dots不兼容。由于dots大量缓存的类型信息,实现复杂,很难单独清理掉缓存信息。


## 内存卸载率

除了以下元数据内存无法卸载外,其余几乎所有(99.9%)元数据都可以被卸载:

- MonoBehavoiur、ScriptableObject之类的脚本类。它们在运行时层面对应的Il2CppClass会被Unity引擎内部引用,无法释放,但可以释放掉绝大多数成员元数据如method
- 被标记`[Serializable]`的类型。与MonoBehaviour类似,它们也可能在序列化过程中被Unity引擎内存引用,无法释放。
- 在本程序集运行过程中使用到,但不涉及到本程序集类型的泛型类。如`List<int>`元数据不会被释放,但`List<MyHotReloadClass>`会被释放

所有未释放的元数据(MonoBehaviour、Serializable类)在再次加载该程序集时**会被复用**。多次加载和卸载同一个程序集,只会发生一次未释放行为,不会导致泄露或者未释放的元数据内存持续增长。

实际项目中,对于大多数程序集可以卸载掉99%以上的元数据内存。

Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
# HotReload Technology

Hot reload technology is used to completely uninstall or reload an assembly, which is suitable for games of the mini-game collection type. This solution only provides **commercial version**.

## Supported features

- Support uninstalling assemblies, uninstalling 100% of the memory occupied by assemblies
- Support reloading assemblies, the code can be arbitrarily changed or even completely different (MonoBehaviour and Scriptable have certain restrictions)
- Support **limiting the set of functions that can be accessed in hot updates of assemblies**, which is suitable for creating sandbox environments in UGC games to avoid damage caused by malicious player code.

## Unsupported features and special requirements

- Require that business code will no longer use objects or functions in the uninstalled assembly, and exit all old logic in execution
- Cannot directly uninstall the dependent assembly, must first uninstall the dependent in reverse dependency order, and then uninstall the dependent. For example, if A.dll depends on B.dll, you need to uninstall A.dll first, then uninstall B.dll
- MonoBehaviour is related to ScriptableObject
- It is required that events or message functions in the overloaded MonoBehaviour, such as Awake and OnEable, do not be added or deleted (but the function body can change)
- It is required that the serialized field name of the script class with the same name in the old assembly does not change after overloading (the type can change)
- If the field type is a custom type A (class or struct or enum) in the uninstallable assembly, it must be given the `[Serializable]` attribute
- The field type `List<A>` is not supported, where A is a type in the uninstallable assembly, please replace it with `A[]`
- Generic types cannot be inherited, such as `class MyScript : CommonScript<int>`
- Some libraries that cache reflection information (this behavior is most common in serialization-related libraries, such as LitJson), need to clean up the cached reflection information after hot reloading
- Destructors, ~XXX(), are not supported. It is also not allowed to instantiate generic classes with destructors whose generic parameters are of this assembly type
- Incompatible with dots. Since dots caches a large amount of type information and the implementation is complex, it is difficult to clean up the cache information separately.

## Memory unloading rate

Except for the following metadata memory that cannot be unloaded, almost all other (99.9%) metadata can be unloaded:

- Script classes such as MonoBehavoiur and ScriptableObject. The Il2CppClass corresponding to them at the runtime level will be referenced by the Unity engine internally and cannot be released, but most member metadata such as method can be released
- Types marked with `[Serializable]`. Similar to MonoBehaviour, they may also be referenced by the Unity engine memory during serialization and cannot be released.
- Generic classes used during the operation of this assembly, but not involving this assembly type. For example, `List<int>` metadata will not be released, but `List<MyHotReloadClass>` will be released

All unreleased metadata (MonoBehaviour, Serializable class) will be reused when the assembly is loaded again. Loading and unloading the same assembly multiple times will only cause one unreleased behavior, which will not cause leaks or continuous growth of unreleased metadata memory.

In actual projects, more than 99% of metadata memory can be unloaded for most assemblies.

0 comments on commit 957d223

Please sign in to comment.