File tree Expand file tree Collapse file tree 1 file changed +65
-6
lines changed Expand file tree Collapse file tree 1 file changed +65
-6
lines changed Original file line number Diff line number Diff line change 1
1
# 常见问题
2
2
3
+ ## [ Serializable] 类型或者Monbehaviour(ScriptableObject)中包含泛型参数为被卸载程序集中类型的泛型字段时崩溃
3
4
4
- ## Json序列化的问题
5
+ 使用JsonUtility或者MonoBehaviour序列化的对象的元数据信息会被引擎缓存。为了支持它们的卸载,我们复用了这些类型信息,即重新加载程序集后,引擎层访问到这些元数据信息会被重新更新为
6
+ 最新的值。
5
7
6
- 程序集卸载后,会卸载所有类型元数据。而几乎所有常用的序列化库都会缓存类型的反射信息,这意味着如果你在代码中使用了Unity的JsonUtility或者LitJson之类的
7
- 序列库,它们会错误地缓存反射信息,导致你第二次(或者第三次)重新加载,并且反序列化时,会出错。
8
+ 由于缓存行为是引擎内部黑箱行为,我们无法复用太复杂的元数据,比如这些类型字段不能是` List<T> ` ,其中T是被卸载程序集中的类型。
8
9
9
- 解决办法有几种:
10
+ 解决办法是将 ` List<T> ` 换成 ` T[] ` 。
10
11
11
- - 给被序列化或者反序列化的类型加上` [Serializable] ` 特性,如果这些类型中成员字段的类型也是class类型` A ` 或者` A[] ` ,则也要给` A ` 也加上` [Serializable] `
12
- - 修改这些反序列化库的代码,在卸载程序集后,清空它们的反射缓存。像Unity的JsonUtility是native实现,无法清空缓存,只能更换为其他Json库。
12
+ 注意,** 仅仅是[ Serializable] 和MonoBhehaviour(ScriptableObject)有此限制** ,其他普通类型的字段可以为任意类型。
13
+
14
+ ## 卸载时存在非法引用了被卸载程序集中对象或者函数的问题
15
+
16
+
17
+ ### UnityEngine.AndroidJavaRunnableProxy
18
+
19
+ 这个对象在CreteJavaProxy时就被创建出来,并且被引擎层持有了,Unity没有提供直接卸载办法。
20
+ 有一个清理办法,但是做不到立马清理,在卸载时仍然会报这种错误:
21
+
22
+ ``` csharp
23
+ IntPtr handle = UnityEngine .AndroidJNIHelper .CreateJavaRunnable (xxx );
24
+ ```
25
+
26
+ 记录下handle.然后不用时清理它:
27
+
28
+ ``` csharp
29
+ UnityEngine .AndrodJNISafe .DelegateGlobalRef (handle );
30
+ ```
31
+
32
+ 但这个操作只是在c#层不再持有这个java Runnable对象。 只有java gc时,才可能真正彻底释放这个 Runnable,此时才会释放C#层的AndroidJavaRunanbleProxy,然后再不会再引用这个被卸载的程序集中对象。
33
+
34
+
35
+ 目前只有一个有效解决办法:
36
+
37
+ 不要直接传递 被卸载的程序集中的delegate 给 AndroidJavaRunnable,而是其他AOT 或者不卸载的程序集中的 一个
38
+ 代理类。 创建 AndroidJavaRunnable时也同时记录下这个代理类。在代理类中保存了指向 实际的被卸载的程序集中的delegate,在卸载前清理这个代码类的 delegate引用为null。代码类似这样:
39
+
40
+ ``` csharp
41
+ class MyRunnableWrapper
42
+ {
43
+ private AndroidJavaRunnable _runnble ;
44
+
45
+ public MyRunnableWrapper (AndroidJavaRunnable runnable )
46
+ {
47
+ _runnble = runnable ;
48
+ }
49
+
50
+ public void Run ()
51
+ {
52
+ _runnble ? .Invoke ();
53
+ }
54
+
55
+ public void Clean ()
56
+ {
57
+ _runnble = null ;
58
+ }
59
+ }
60
+
61
+ static void Register (AndroidJavaRunnable runnable )
62
+ {
63
+ var wrapper = new MyRunnableWrapper (runnable );
64
+
65
+ // 将这个传递给Java层
66
+ var runner = UnityEngine .AndroidJNIHelper .CreateJavaRunnable (wrapper .Run );
67
+
68
+ // 卸载前清理
69
+ wrapper .Clean ();
70
+ }
71
+ ```
13
72
You can’t perform that action at this time.
0 commit comments