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#中也是一样的。

返回:Unity代码热更新方案 JSBinding + SharpKit 首页

JSBinding + SharpKit / 原理篇:内存管理与垃圾回收的更多相关文章

  1. JVM原理(Java代码编译和执行的整个过程+JVM内存管理及垃圾回收机制)

    转载注明出处: http://blog.csdn.net/cutesource/article/details/5904501 JVM工作原理和特点主要是指操作系统装入JVM是通过jdk中Java.e ...

  2. Java之美[从菜鸟到高手演变]之JVM内存管理及垃圾回收

    很多Java面试的时候,都会问到有关Java垃圾回收的问题,提到垃圾回收肯定要涉及到JVM内存管理机制,Java语言的执行效率一直被C.C++程序员所嘲笑,其实,事实就是这样,Java在执行效率方面确 ...

  3. JVM内存管理及垃圾回收【转】

    很多Java面试的时候,都会问到有关Java垃圾回收的问题,提到垃圾回收肯定要涉及到JVM内存管理机制,Java语言的执行效率一直被C.C++程序员所嘲笑,其实,事实就是这样,Java在执行效率方面确 ...

  4. C#内存管理与垃圾回收

    垃圾回收还得从根说起,就像生儿育女一样. 根:根是一个位置,存放一个指针,该指针指向托管堆中的一个对象,或是一个空指针不指向任何对象,即为null.根存在线程栈或托管堆中,大部分的跟都在线程栈上,因为 ...

  5. 使用虚幻引擎中的C++导论(四-内存管理与垃圾回收)(终)

    使用虚幻引擎中的C++导论(四)(终) 第一,这篇是我翻译的虚幻4官网的新手编程教程,原文传送门,有的翻译不太好,但大体意思差不多,请支持我O(∩_∩)O谢谢. 第二,某些细节操作,这篇文章省略了,如 ...

  6. Java内存管理和垃圾回收

    笔记,深入理解java虚拟机 Java运行时内存区域 程序计数器,线程独占,当前线程所执行的字节码的行号指示器,每个线程需要记录下执行到哪儿了,下次调度的时候可以继续执行,这个区是唯一不会发生oom的 ...

  7. V8 内存管理和垃圾回收机制总结

    这篇文章主要介绍 V8 的内存管理和垃圾回收知识. V8 内存管理及垃圾回收机制浅析 由于 V8 引擎的原因,Node 在操作大内存对象时受到了一些限制,在 64 位的机器上,默认最大操作的对象大小约 ...

  8. javascript中的内存管理和垃圾回收

    前面的话 不管什么程序语言,内存生命周期基本是一致的:首先,分配需要的内存:然后,使用分配到的内存:最后,释放其内存.而对于第三个步骤,何时释放内存及释放哪些变量的内存,则需要使用垃圾回收机制.本文将 ...

  9. 面试题之C# 内存管理与垃圾回收

    面试题之C# 内存管理与垃圾回收 你说说C# 的内存管理是怎么样的 这句话我记了一个多礼拜了, 自从上次东北师大面试之后, 具体请看<随便扯扯东北师大的面试>. 国庆闲着没事, 就大概了解 ...

  10. .NET基础 (05)内存管理和垃圾回收

    内存管理和垃圾回收1 简述.NET中堆栈和堆的特点和差异2 执行string abc="aaa"+"bbb"+"ccc"共分配了多少内存3 ...

随机推荐

  1. 《day15---多线程安全问题_JDK1.5的锁机制》

    //15同步问题的分析案例以及解决思路 //两个客户到一个银行去存钱,每个客户一次存100,存3次. //问题,该程序是否有安全问题,如果有,写出分析过程,并定于解决方案. /* 发现运行结果: su ...

  2. 关于jquery.bind

      随着现在JQuery这个javascript的越来越强大,在我们平常的前端UI开发,如果不使用JQuery,说明你已经很out了.今天我们来学习一下 JQuery的bind事件.虽然,这个话题被很 ...

  3. HDU 3333 - Turing Tree (树状数组+离线处理+哈希+贪心)

    题意:给一个数组,每次查询输出区间内不重复数字的和. 这是3xian教主的题. 用前缀和的思想可以轻易求得区间的和,但是对于重复数字这点很难处理.在线很难下手,考虑离线处理. 将所有查询区间从右端点由 ...

  4. PAT 07-2 A+B和C

    有两个值得注意的地方:1.变长数组(VLA)的使用,没想到PAT上的OJ竟然支持C99,一开始不知道就没用,看了看别人的,既然,还是用吧, 它有一点我不太喜欢,它不能像一般数组那样在声明时通过赋一个0 ...

  5. MyEclipse 安装目录下找不到Common目录

    最近在安装了MyEclipse,由于是自己指定的安装目录,在成功安装后要破解的时候却发现找不到安装目录下的Common目录,很是郁闷,后来发现如下: MyEclipse启动后的上方导航中找到MyEcl ...

  6. hdu 2080

    ps:水题...求夹角...先求出COS,然后用acos 代码: #include "stdio.h" #include "math.h" int main() ...

  7. oracle的存储结构

    表空间 当一个用户被创建以后,随之就要为用户分配数据存储的空间,这在oracle中成为“表空间”(Tablespace). 在数据库中创建用户时,基于应用性能和管理的考虑,最好为不同的用户创建独立的表 ...

  8. 修改主机名Ubuntu

    主机名存放在/etc/hostname 修改保存即可

  9. 文件IO和标准IO

    2015.2.26 星期四,阴天 今天的内容主要是文件IO man 手册的分册: man -f open 查看那些分册中有openman 1 -- 普通的命令程序man 2 -- 系统调用man 3 ...

  10. 【转】CSS3 transition规范的实际使用经验

    原文转自:http://blog.jobbole.com/56243/ 本篇文章主要讲述CSS3 transition规范和在不同浏览器之间的使用差异,关于具体解决方法或如何规避问题的意见可以参考另一 ...