public static void ShutdownJSEngine() { shutDown = true; /* * 在 Shutdown 时,先主动删除 CSRepresentedObject * 现在已经没有必要再维护 id -> CSR.. 的关系了 * 移除后,CSR.. 有可能还被其他地方引用,所以在这个函数中调用C# GC,也不一定会调用到 CSR.. 的析构 * 后来在某个时刻析构被调用,在析构函数里有 removeJSCSRel ,那里会判断 round 是上一轮的所以忽略 */ List <int> keysToRemove = new List <int>(); List <int> hashsToRemove = new List <int>(); foreach (var KV in mDictionary1) { JS_CS_Rel rel = KV.Value; if (rel.csObj is WeakReference) { if ((rel.csObj as WeakReference).Target is CSRepresentedObject) { keysToRemove.Add(KV.Key); hashsToRemove.Add(rel.hash); } } } foreach (var k in keysToRemove) { mDictionary1.Remove(k); } foreach (var h in hashsToRemove) { mDictionary2.Remove(h); } // // 并GC // System.GC.Collect(); int Count = mDictionary1.Count; // There is a JS_GC called inside JSApi.ShutdownJSEngine #if UNITY_EDITOR // DO NOT really cleanup everything, because we wanna start again JSApi.ShutdownJSEngine(0); #else JSApi.ShutdownJSEngine(1); #endif StringBuilder sb = new StringBuilder(); sb.AppendLine("After JSApi.ShutdownJSEngine: "); sb.Append("mDictionary1 count " + Count + " -> " + mDictionary1.Count + ", left elements(should only contain JSComponent):\n"); /* * 到这里 mDictionary1 和 mDictionary2 应该只剩余 JSComponent 及其子类,原因是: * 除了 JSComponent 外,其他东西都应该在 JSApi.ShutdownJSEngine(0) 后被移除(他里面调用了 JS_GC) * 而 JSComponent 是没有垃圾回收回调的,他是在 OnDestroy 时从这2个字典里移除的 * 这时候可能他的 OnDestroy 还没有执行,所以这2个字典里还会有他们 */ List <int> Keys = new List <int>(mDictionary1.Keys); foreach (var K in Keys) { if (!mDictionary1.ContainsKey(K)) { continue; } JS_CS_Rel Rel = mDictionary1[K]; sb.AppendLine(K.ToString() + " " + Rel.name); } Debug.Log(sb); allCallbackInfo.Clear(); JSMgr.MoveJSCSRel2Old(); mDictJSFun1.Clear(); mDictJSFun2.Clear(); evaluatedScript.Clear(); CSRepresentedObject.s_objCount = 0; CSRepresentedObject.s_funCount = 0; jsEngineRound++; }
public static void ShutdownJSEngine() { shutDown = true; // // remove CSRepresentedObject first // no need to maintain id -> CSRepresentedObject now // // after remove, CSRepresentedObject may still be referenced, and ~CSRepresentedObject may not be called // some times later ~CSRepresentedObject is called -> removeJSCSRel -> round is ignored because it is last round // List <int> keysToRemove = new List <int>(); List <int> hashsToRemove = new List <int>(); foreach (var KV in mDictionary1) { JS_CS_Rel rel = KV.Value; if (rel.csObj is WeakReference) { if ((rel.csObj as WeakReference).Target is CSRepresentedObject) { keysToRemove.Add(KV.Key); hashsToRemove.Add(rel.hash); } } } foreach (var k in keysToRemove) { mDictionary1.Remove(k); } foreach (var h in hashsToRemove) { mDictionary2.Remove(h); } System.GC.Collect(); int Count = mDictionary1.Count; // There is a JS_GC called inside JSApi.ShutdownJSEngine #if UNITY_EDITOR // DO NOT really cleanup everything, because we wanna start again JSApi.ShutdownJSEngine(0); #else JSApi.ShutdownJSEngine(1); #endif StringBuilder sb = new StringBuilder(); sb.AppendLine("After JSApi.ShutdownJSEngine: "); sb.Append("mDictionary1 count " + Count + " -> " + mDictionary1.Count + ", left elements(should only contain JSComponent):\n"); // // here, mDictionary1 and mDictionary2 should only contain JSComponent and his subclasses, because: // everything should be removed after JSApi.ShutdownJSEngine(0) (it calls calls JS_GC) // JSComponent is nomally be removed during OnDestroy, but his OnDestroy may not be called yet here // List <int> Keys = new List <int>(mDictionary1.Keys); foreach (var K in Keys) { if (!mDictionary1.ContainsKey(K)) { continue; } JS_CS_Rel Rel = mDictionary1[K]; sb.AppendLine(K.ToString() + " " + Rel.name); } Debug.Log(sb); allCallbackInfo.Clear(); JSMgr.MoveJSCSRel2Old(); mDictJSFun1.Clear(); mDictJSFun2.Clear(); evaluatedScript.Clear(); CSRepresentedObject.s_objCount = 0; CSRepresentedObject.s_funCount = 0; jsEngineRound++; }