您好,登錄后才能下訂單哦!
本篇文章給大家分享的是有關怎么分析JSBinding + SharpKit 內存管理與垃圾回收的原理,小編覺得挺實用的,因此分享給大家學習,希望大家閱讀完這篇文章后可以有所收獲,話不多說,跟著小編一起來看看吧。
C# 和 JS 都有垃圾回收機制,需要保證 2 者能夠分工協作。
類對象
類在C#中是引用類型。我們在 C# 中維護了2個map,保存 C# 對象和 JS 對象的一一對應關系。
舉一個例子,看以下代碼
1 // C# 2 List<int> lst = new List<int>(); 3 4 // JS 5 var lst = new System.Collections.Generic.List$1.ctor(System.Int32.ctor);
從C#返回一個對象到 JS 以及后續的過程是這樣的:
1) C# 獲得一個表示JS對象的ID。
1 // 文件:System_Collections_Generic_List77.javascript 2 _jstype.definition.ctor = function(t0) { CS.Call(5, 249, 0, true, this, t0.getNativeType()); } // 1) 這里的 this 傳到 C#后,C#得到一個對象ID
2) C# 創建一個 List csObj 對象。
3) 保存2種對象的一一對應關系。
1 // 存儲對應關系,偽代碼,具體可看 JSMgr.addJSCSRel 函數! 2 map1[jsObjID] = csObj; 3 map2[csObj.hashCode] = jsObjID;
注意,由于我們保存了 csObj 對象,那么我們必須在某個時刻就把他從map中移除,否則這個對象永遠不會被C# GC 給回收。
4) 給 JS 對象注冊 finalizer 回調函數,當他被 JS GC 回收時,會通知我們的回調。
在回調中做的事情就是從map中移除對 csObj 的引用,這樣我們就沒有主動握住 csObj 了,那他到某個時刻 自然就被回收了。
1 // 文件:System_Collections_Generic_List77Generated.cs
2
3 static bool ListA1_ListA11(JSVCall vc, int argc)
4 {
5 int _this = JSApi.getObject((int)JSApi.GetType.Arg); // 1) 獲取JS對象ID
6 JSApi.attachFinalizerObject(_this); // 4) 給 JS 對象注冊 finalizer 函數,當他被垃圾回收時,會通知我們的回調
7 --argc;
8
9 ConstructorInfo constructor = JSDataExchangeMgr.makeGenericConstructor(typeof(System.Collections.Generic.List<>), constructorID0);
10 if (constructor == null) return true;
11
12 int len = argc - 1;
13 if (len == 0)
14 {
15 JSMgr.addJSCSRel(_this,
constructor.Invoke(null, new object[]{}));// 2), 3) 創建 C# 對象,保存一一對應關系
16 }
17
18 return true;
19 }
5) 任何時刻,當要從C#返回一個對象到JS時,都會查找是否已經有對應的 JS 對象了。如果有,就返回已經保存的那個。如果沒有,才創建一個對應的 JS 對象返回給 JS。
小結:對于類對象,我們存儲了JS對象和CS對象的一一對應關系。JS對象仍然是完全受 JS GC 管理,什么該被回收就什么時候被回收。而對于CS對象,通過往JS對象注冊垃圾回收事件,當JS對象被回收時我們將得到通知,那時候我們就可以主動去除對CS對象的引用了。
結構體對象
結構體在C#中是值類型的。不可能存儲一一對應關系。從C#返回結構體對象到JS時,每次都重新創建一個對象出來,返回給JS。只能通過JS對象找到對應的C#對象,反過來是行不通的。
存儲關系變成:
1 // 存儲對應關系,偽代碼,具體可看 JSMgr.addJSCSRel 函數!
2 map1[jsObjID] = csObj;
3 // map2[csObj.hashCode] = jsObjID; // 沒有這個了!
垃圾回收控制跟類對象是一樣的。
注意:目前代碼里 Vector2,Vector3 是用JS寫了一遍(以后還會增加)。他們和上面說到的結構體對象的存儲方法沒有什么關系。
每當 從 JS->CS 時,根據JS對象的xyz值構造一個C#對象來使用。
每個從 CS->JS 時,根據CS對象的xyz值構造一個 JS 對象。
(不好理解?想象一下 int 如何 JS->CS,CS->JS? 目前V2, V3和 int 的傳遞是類似的,在 JS 和 CS 端都各有各自的數據結構)
(還是不好理解?群里問吧,或者問我)
純JS對象在C#中的存儲
上面所說的類對象和結構體對象的存儲有一個共同點:JS和CS兩端都知道要存儲的對象類型是什么。比如說 List,GameObject,2邊都很了解這2個類,都能對他們的對象進行處理。
純JS對象是指,只有JS有類定義,C#并不清楚這個類。
1 // JS 代碼 2 3 JsTypes.push( { 4 fullname: "DebugMessages.Message", 5 Kind: "Class", 6 definition: { 7 ctor: function (txt){ 8 this.txt = txt; 9 } 10 } 11 }); 12 13 var l = new System.Collections.Generic.List$1.ctor(DebugMessages.Message.ctor); 14 l.Add(new DebugMessages.Message("hello"); 15 l.Add(new DebugMessages.Message("world");
Line13,創建一個 List,C#端構造 List 時會發現類型名是 "DebugMessage.Message",根據這個名字查找不到 System.Type(請看 JSDataExchange.GetTypeByName 函數)。
怎么辦呢?可不可以這樣,當C#找不到類型的時候,就直接用 List<int>,int表示JS對象ID。這樣不是挺好嗎?
是的,一開始就是這么做的。請看 Line14,new一個JS對象并傳遞給C#,C#存儲了他的ID,看起來很美好。
但!是!這個JS對象接下去就沒有人引用他了,如果發生GC,那個對象就要被回收。而C#那邊還存著一個int,等一下要用的時候就找不著JS對象了……
當你把一個JS函數設置給C# Delegate 時,也存在相同的問題。
所以,在C#中存儲這個JS對象時,要增加JS對象的引用!
我增加了一個 CSRepresentedObject 類,來完成這個功能。
(這里面還多了個小細節:使用了 WeakReference 類,具體可以看下代碼,缺他好像不行)
1 public class CSRepresentedObject 2 { 3 public static int s_objCount = 0; 4 public static int s_funCount = 0; 5 6 //不要直接創建這個對象,應該調用 JSDataExchangeMgr.getObject 7 public CSRepresentedObject(int jsObjID, bool bFunction = false) 8 { 9 this.jsEngineRound = JSMgr.jsEngineRound; 10 this.jsObjID = jsObjID; 11 this.bFunction = bFunction; 12 JSMgr.addJSCSRel(jsObjID, this, true); 13 14 if (bFunction) 15 s_funCount++; 16 else 17 s_objCount++; 18 19 // 通常是1,不會加的 20 int refCount = JSApi.incRefCount(jsObjID); 21 //Debug.Log(new StringBuilder().AppendFormat("+ CSRepresentedObject {0} Ref[{1}] Fun[{1}]", jsObjID, refCount, bFunction ? 1 : 0)); 22 } 23 ~CSRepresentedObject() 24 { 25 if (bFunction) 26 s_funCount--; 27 else 28 s_objCount--; 29 30 int refCount = JSApi.decRefCount(jsObjID); 31 if (refCount <= 0) 32 { 33 JSMgr.removeJSCSRel(jsObjID, this.jsEngineRound); 34 if (bFunction) 35 { 36 JSMgr.removeJSFunCSDelegateRel(jsObjID); 37 } 38 } 39 else 40 { 41 Debug.LogError(";;;//IIL.x&"); 42 } 43 //Debug.Log(new StringBuilder().AppendFormat("- CSRepresentedObject {0} Ref[{1}] Fun[{1}]", jsObjID, refCount, bFunction ? 1 : 0)); 44 } 45 public int jsObjID; 46 public bool bFunction; 47 int jsEngineRound; 48 }
純C#對象在JS中的存儲
目前已知這種情況只發生在,當傳遞一個C#函數到JS時。(例子:TestEasingFunctions.cs)
在JS中也定義了一個叫做 JSRepresentedObject 的類來處理。(myclrhandler.javascript)
不過比上一種情況要簡單得多。這種情況處理后就變成和 “類對象” 一毛一樣了。
注意:C#對象存儲在JS中,JS根本無法使用拿到的C#對象,他只能起到一個過渡作用而已。
JS對象存儲在C#中也是一樣的。
以上就是怎么分析JSBinding + SharpKit 內存管理與垃圾回收的原理,小編相信有部分知識點可能是我們日常工作會見到或用到的。希望你能通過這篇文章學到更多知識。更多詳情敬請關注億速云行業資訊頻道。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。