|
1 | 1 | # Best Practices |
2 | 2 |
|
3 | | -## Unity version recommendation |
| 3 | +## Unity Version Recommendation |
4 | 4 |
|
5 | | -It is recommended to use `2020.3.x(x >= 21)` series and `2021.3.x` series, which are the most stable. |
| 5 | +Recommend using `2020.3.x(x >= 21)` series and `2021.3.x` series, which are the most stable. |
6 | 6 |
|
7 | | -## It is recommended to mount the startup script to the first loaded hot update scene after the hot update is completed |
| 7 | +## Don't Save assemblyBytes After Assembly.Load |
8 | 8 |
|
9 | | -It is recommended to mount the startup script to the startup hot update scene, so that the non-hot update project can be transformed into a hot update project with zero changes, and no reflection operation is required. |
| 9 | +Don't save the assembly's byte[] data after calling Assembly.Load, as Assembly.Load automatically makes a copy internally. |
10 | 10 |
|
11 | | -## When `RuntimeApi.LoadMetadataForAOTAssembly` is called |
| 11 | +## Recommend Mounting Startup Scripts to the First Hot Update Scene Loaded After Hot Update Completion |
12 | 12 |
|
13 | | -You just need to call it before using AOT generics (you only need to call it once). In theory, the earlier the loading, the better. In practice, a more reasonable time is after the hot update is completed, or after the hot update dll is loaded but before any code is executed. If the dll that supplements the metadata is also entered into the main package as an additional data file, it will be better loaded when the main project starts. Please refer to [HybridCLR_trial](https://github.com/focus-creative-games/hybridclr_trial) project |
| 13 | +Recommend mounting startup scripts to the startup hot update scene, which allows zero-modification conversion of non-hot update projects to hot update projects without requiring any reflection operations. |
14 | 14 |
|
15 | | -## Do not use reflection to interact with native and interpreter performance-sensitive occasions, you should use Delegate or virtual function |
| 15 | +## Timing of `RuntimeApi.LoadMetadataForAOTAssembly` Calls |
16 | 16 |
|
17 | | -Taking the Update function as an example, most people would think that the interaction between the main project and the update part is like this: |
| 17 | +You only need to call it before using AOT generics (only needs to be called once), and theoretically the earlier the better. In practice, reasonable timing is after hot update completion, or after hot update dll loading but before executing any code. If supplemental metadata dlls are also packaged into the main package as additional data files, loading them during main project startup is better. Refer to the [HybridCLR_trial](https://github.com/focus-creative-games/hybridclr_trial) project |
| 18 | + |
| 19 | +## `Assembly.Load` or `RuntimeApi.LoadMetadataForAOTAssembly` Taking Too Long, Causing Game Stuttering |
| 20 | + |
| 21 | +You can put them in other threads for asynchronous loading. |
| 22 | + |
| 23 | +## For Performance-Sensitive Interactions Between Native and Interpreter Parts, Don't Use Reflection - Use Delegates or Virtual Functions Instead |
| 24 | + |
| 25 | +Taking the Update function as an example, most people would think of interaction between the main project and hot update part like this: |
18 | 26 |
|
19 | 27 | ```csharp |
20 | | -var klass = ass. GetType("App"); |
21 | | -var method = klass. GetMethod("Update"); |
| 28 | +var klass = ass.GetType("App"); |
| 29 | +var method = klass.GetMethod("Update"); |
22 | 30 | method.Invoke(null, new object[] {deltaTime}); |
23 | 31 | ``` |
24 | 32 |
|
25 | | -The disadvantage of this method is that the cost of reflection is high. In case there are parameters and additional gc, there is actually a more efficient method. There are two main ways: |
| 33 | +The disadvantage of this approach is high reflection cost, and if parameters are involved, additional GC occurs. Actually, there are more efficient methods. There are mainly two approaches: |
26 | 34 |
|
27 | | -### The hot update layer returns a Delegate |
| 35 | +### Hot Update Layer Returns a Delegate |
28 | 36 |
|
29 | 37 | ```csharp |
30 | | -// Hotfix.asmdf hot update part |
31 | | -class app |
| 38 | +// Hotfix.asmdf hot update part |
| 39 | +class App |
32 | 40 | { |
33 | | - public static Action<float> GetUpdateDelegate() |
34 | | - { |
35 | | - return Update; |
36 | | - } |
37 | | - |
38 | | - public static void Update(float deltaTime) |
39 | | - { |
40 | | - } |
| 41 | + public static Action<float> GetUpdateDelegate() |
| 42 | + { |
| 43 | + return Update; |
| 44 | + } |
| 45 | + |
| 46 | + public static void Update(float deltaTime) |
| 47 | + { |
| 48 | + } |
41 | 49 | } |
42 | 50 |
|
43 | 51 | // Main.asmdf main project |
44 | | -var klass = ass. GetType("App"); |
45 | | -var method = klass. GetMethod("GetUpdateDelegate"); |
46 | | -var updateDel = (Action<float>)method. Invoke(null, null); |
| 52 | +var klass = ass.GetType("App"); |
| 53 | +var method = klass.GetMethod("GetUpdateDelegate"); |
| 54 | +var updateDel = (Action<float>)method.Invoke(null, null); |
47 | 55 |
|
48 | 56 | updateDel(deltaTime); |
49 | 57 | ``` |
50 | 58 |
|
51 | | -### Through Delegate.Create, create the corresponding Delegate according to MethodInfo |
| 59 | +### Use Delegate.Create to Create Corresponding Delegate Based on MethodInfo |
52 | 60 |
|
53 | 61 | ```csharp |
54 | | -var klass = ass. GetType("App"); |
55 | | -var method = klass. GetMethod("Update"); |
| 62 | +var klass = ass.GetType("App"); |
| 63 | +var method = klass.GetMethod("Update"); |
56 | 64 | updateDel = (Action<float>)System.Delegate.CreateDelegate(typeof(Action<float>), null, method); |
57 | 65 | updateDel(deltaTime); |
58 | 66 | ``` |
59 | 67 |
|
60 | | -## 2021 version don't use `faster(smaller) builds` option |
| 68 | +## Don't Use `faster(smaller) builds` Option in 2021 Versions |
61 | 69 |
|
62 | | -Since the 2021.3.x LTS version, il2cpp has fully supported the `full generic sharing` technology. When the `Il2Cpp Code Generation` option in Build Settings is `faster runtime`, it is a standard generic sharing mechanism, and `faster(smaller) builds` open when |
63 | | -`full generic sharing` mechanism. |
| 70 | +Starting from 2021.3.x LTS versions, il2cpp fully supports `full generic sharing` technology. When the `Il2Cpp Code Generation` option in Build Settings is `faster runtime`, it uses the standard generic sharing mechanism; when it's `faster(smaller) builds`, it enables the `full generic sharing` mechanism. |
64 | 71 |
|
65 | | -When `full generic sharing` is enabled, each generic function (regardless of whether the generic parameter is a value type or a class type) will completely sharing a code. The advantage is to save the size of the package body, and the disadvantage is that it greatly hurts the performance of the generic function . The fully generic shared code is sometimes several to ten times slower than the standard generic shared code, and even worse than the purely interpreted version. Therefore it is strongly recommended to **not enable** the `faster(smaller) builds` option. |
| 72 | +When `full generic sharing` is enabled, each generic function (regardless of whether generic parameters are value types or class types) completely shares a single copy of code. The advantage is saving package size, but the disadvantage is severely hurting generic function performance. Fully generic shared code compared to standard generic shared code can sometimes be several to dozens of times slower, even worse than pure interpretation versions. Therefore, it's strongly recommended to **not enable** the `faster(smaller) builds` option. |
0 commit comments