-
Notifications
You must be signed in to change notification settings - Fork 719
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[Unity] C# 调用 JS 时因 GC 触发导致参数变成无效对象 #681
Comments
图中看不出你是怎么使用Action的。 原理上来说,每个到C#变成delegate的JS函数,在C++侧都会有一个JSFunction对象,使用PersistentHandler持有它。 所以你这个case就挺离奇,看看你能不能按这个思路先查查。 |
@zombieyang 感谢回复。 Action 是这样的,在 C# 这边有个事件处理器,在 JS 调用 C# 的方法传入了一个 Function 作为事件监听者。当事件派发的时候,通过这个 Action 回调到 JS 层。 // this.onLoopCompleteBind 是一个 JS 的 Function,传入到 C# 生成那个 Action。
this.onLoopCompleteBind = this.onLoopCompleteDBEvent.bind(this);
this.armatureComponent.addDBEventListener(EventObject.LOOP_COMPLETE, this.onLoopCompleteBind);
private onLoopCompleteDBEvent(type: string, eventObject: dragonBones.EventObject) {
if (eventObject && eventObject.animationState) { // JS 报错行
this.onLoopComplete(eventObject);
}
} 现在的问题并不是这个 JSFunction 被释放了。而是调用这个 Function 的时候传入的参数从 ObjectPool 里被移除了,这样就会导致参数传到 JS 后。在 JS 里使用这个参数的时候(上面代码块中的 [Puerts.MonoPInvokeCallback(typeof(Puerts.V8FunctionCallback))]
private static void G_animationState(IntPtr isolate, IntPtr info, IntPtr self, int paramLen, long data)
{
try
{
var obj = Puerts.Utils.GetSelf((int)data, self) as DragonBones.EventObject;
var result = obj.animationState; // C# 报错行
Puerts.ResultHelper.Set((int)data, isolate, info, result);
}
catch (Exception e)
{
Puerts.PuertsDLL.ThrowException(isolate, "c# exception:" + e.Message + ",stack:" + e.StackTrace);
}
} |
这个EventObject,基类是不是一个C#类,然后JS侧将其extends了?#65 |
EventObject 是 C# 的一个类,但没有在 JS 层继承他,和 #65 不太一样。 但是今天有点新的发现,在 C# 调到 JS 时传的参数 eventObject 是从一个对象池(非 Puerts.ObjectPool)中取出来了,因为是复用的对象,出问题前也多次将这个对象传入到 JS。猜测是不是 GC 的时候清理之前的对象,导致这次的复用对象也被清理? |
看上去有这么个可能。 https://github.com/Tencent/puerts/blob/master/unity/native_src/Src/JSFunction.cpp#L98 |
感谢两位的回复。 经过测试分析,发现我的应用场景可能确实是跟对象池有关系。但是我做了另外一个测试,也能重现问题。 示例代码
public static void TestEventObject(Action<string, DragonBones.EventObject> handler)
{
Game.Instance.ScheduleUpdate(() =>
{
var eventObject = new DragonBones.EventObject();
handler(eventObject.type, eventObject); // 注释 A
handler(eventObject.type, eventObject); // 注释 B
handler(eventObject.type, eventObject);
handler(eventObject.type, eventObject);
handler(eventObject.type, eventObject);
handler(eventObject.type, eventObject);
handler(eventObject.type, eventObject);
handler(eventObject.type, eventObject);
handler(eventObject.type, eventObject);
handler(eventObject.type, eventObject);
});
}
[Puerts.MonoPInvokeCallback(typeof(Puerts.V8FunctionCallback))]
private static void G_type(IntPtr isolate, IntPtr info, IntPtr self, int paramLen, long data)
{
try
{
var obj = Puerts.Utils.GetSelf((int)data, self) as DragonBones.EventObject;
var result = obj.type; // 报错行
Puerts.PuertsDLL.ReturnString(isolate, info, result);
}
catch (Exception e)
{
Puerts.PuertsDLL.ThrowException(isolate, "c# exception:" + e.Message + ",stack:" + e.StackTrace);
}
}
onTestEventObject(type: string, eventObject: dragonBones.EventObject): void {
if (eventObject && eventObject.type) { // 报错行
}
}
test(): void {
UnityTest.TestEventObject(this.onTestEventObject.bind(this));
} 问题分析
|
大概明白问题在哪了。顺便确认一下你用的plugin版本是v8还是quickjs? |
v8 |
https://github.com/Tencent/puerts/tree/681 |
看 commit 信息,似乎改过 native 的代码了,请问哪里可以下载到对应编译好的库文件 |
找到了,应该是这个吧?https://github.com/Tencent/puerts/actions/runs/1932215308 |
是的 |
@zombieyang 经过测试,在上面的例子和我的实际应用场景中都不会再出现错误。 问题应该是已经修复了,再次感谢! |
好,你先用着,后续我优化好代码之后再合入master |
好的,谢谢 |
我把这个合并到1.2.2上了,情况好了一些,但是没有完全好
|
(cherry picked from commit 79be1da7ddab1cb55e88117fc5fc6df50569d549)
This reverts commit b24aefc.
This reverts commit b24aefc.
This reverts commit b24aefc.
This reverts commit b24aefc.
This reverts commit b24aefc.
详细描述
Unity 2019 的环境中,在 C# 调到 JS 的方法时(图中代码:497 行),传到 JS 的参数,在执行 PuertsDLL.InvokeJSFunction 的时候从对象池里移除掉了,具体可以看图中的调用堆栈。这样导致传到 JS 层的对象就无法正常使用了。
问题分析
目前看起来应该是在 C++ 的 JSEngine.cpp 中的 OnGarbageCollected 方法因为 gc 被触发,然后代码调回到 C# 的 StaticCallbacks.GeneralDestructor 方法,导致对象从对象池中移除。
问题
The text was updated successfully, but these errors were encountered: