位置: 编程技术 - 正文

Mono为何能跨平台?聊聊CIL(MSIL)(mono为什么不能用了)

编辑:rootadmin

推荐整理分享Mono为何能跨平台?聊聊CIL(MSIL)(mono为什么不能用了),希望有所帮助,仅作参考,欢迎阅读内容。

文章相关热门搜索词:mono倒闭了吗,mono倒闭了吗,mono move,mono跨平台,mono怎么没有了,mono为什么不能用了,mono跨平台,mono跨平台,内容如对您有帮助,希望把文章链接给更多的朋友!

  本文系转载。原创作者:陈嘉栋(慕容小匹夫),原文链接:   

前言:

  其实小匹夫在U3D的开发中一直对U3D的跨平台能力很好奇。到底是什么原理使得U3D可以跨平台呢?后来发现了Mono的作用,并进一步了解到了CIL的存在。所以,作为一个对Unity3D跨平台能力感兴趣的U3D程序猿,小匹夫如何能不关注CIL这个话题呢?那么下面各位看官就拾起语文老师教导我们的作文口诀(Why,What,How),和小匹夫一起走进CIL的世界吧~

Why?

  回到本文的题目,U3D或者说Mono的跨平台是如何做到的?   如果换做小匹夫或者看官你来做,应该怎么实现一套代码对应多种平台呢?   其实原理想想也简单,生活中也有很多可以参考的例子,比如下图(谁让小匹夫是做移动端开发的呢,只能物尽其用从自己身边找例子了T.T):                                                      通用手机充电线   像这样一根线,管你是安卓还是ios都能充电。所以从这个意义上,这货也实现了跨平台。那么我们能从它身上学到什么呢?对的,那就是从一样的能源(电)到不同的平台(ios,安卓)之间需要一个中间层过度转换一下。   那么来到U3D为何能跨平台,简而言之,其实现原理在于使用了叫CIL(Common Intermediate Language通用中间语言,也叫做MSIL微软中间语言)的一种代码指令集,CIL可以在任何支持CLI(Common Language Infrastructure,通用语言基础结构)的环境中运行,就像.NET是微软对这一标准的实现,Mono则是对CLI的又一实现。由于CIL能运行在所有支持CLI的环境中,例如刚刚提到的.NET运行时以及Mono运行时,也就是说和具体的平台或者CPU无关。这样就无需根据平台的不同而部署不同的内容了。所以到这里,各位也应该恍然大了。代码的编译只需要分为两部分就好了嘛:   ● 从代码本身到CIL的编译(其实之后CIL还会被编译成一种位元码,生成一个CLI assembly)   ● 运行时从CIL(其实是CLI assembly,不过为了直观理解,不必纠结这种细节)到本地指令的即时编译(这就引出了为何U3D官方没有提供热更新的原因:在iOS平台中Mono无法使用JIT引擎,而是以Full AOT模式运行的,所以此处说的额即时编译不包括IOS)

What?

  上文也说了CIL是指令集,但是不是还是太模糊了呢?所以语文老师教导我们,描述一个东西时肯定要先从外貌写起。遵循老师的教导,我们不妨先通过工具来看看CIL到底长什么样。工具就是ildasm了。下面小匹夫写一个简单的.cs看看生成的CIL代码长什么样。 C#代码:

CIL代码:

  好啦。代码虽然简单,但是也能说明足够多的问题。那么和CIL的第一次亲密接触,能给我们留下什么直观的印象呢?   ● 以“.”一个点号开头的,例如上面这份代码中的:.class、.method 。我们称之为CIL指令(directive),用于描述.NET程序集总体结构的标记。为啥需要它呢?因为你总得告诉编译器你处理的是啥吧。   ● 貌似CIL代码中还看到了private、public这样的身影。姑且称之为CIL特性(attribute)。它的作用也很好理解,通过CIL指令并不能完全说明.NET成员和类,针对CIL指令进行补充说明成员或者类的特性的。市面上常见的还有:extends,implements等等。   ● 每一行CIL代码基本都有的,对,那就是CIL操作码咯。小匹夫从网上找了一份汉化的操作码表放在附录部分,当然英文版的你的vs就有。 直观的印象有了,但是离我们的短期目标,说清楚(或者说介绍个大概)CIL是What,甚至是终极目标,搞明白Uniyt3D为何能跨平台还有2万4千9百里的距离。   好啦,话不多说,继续乱侃。   参照附录中的操作码表,对照可以总结出一份更易读的表格。那就是如下的表啦。                             表 1-1 操作码表(简略)           在此,小匹夫想请各位认真读表,然后心中默数3个数,最后看看都能发现些什么。

基于堆栈

  如果是小匹夫的话,第一感觉就是基本每一条描述中都包含一个”栈“。不错,CIL是基于堆栈的,也就是说CIL的VM(mono运行时)是一个栈式机。这就意味着数据是推入堆栈,通过堆栈来操作的,而非通过CPU的寄存器来操作,这更加验证了其和具体的CPU架构没有关系。为了说明这一点,小匹夫举个例子好啦。   大学时候学单片机(大概是,记不清了)的时候记得做加法大概是这样的:

  其中的eax是啥?寄存器。所以如果CIL处理数据要通过cpu的寄存器的话,那也就不可能和cpu的架构无关了。   当然,CIL之所以是基于堆栈而非CPU的另一个原因是相比较于cpu的寄存器,操作堆栈实在太简单了。回到刚才小匹夫说的大学时候曾经学过的单片机那门课程上,当时记得各种寄存器,各种标志位,各种。。。,而堆栈只需要简单的压栈和弹出,因此对于虚拟机的实现来说是再合适不过了。所以想要更具体的了解CIL基于堆栈这一点,各位可以去看一下堆栈方面的内容。这里小匹夫就不拓展了。

面向对象

  那么第二感觉呢?貌似附录的表中有new对象的语句呀。嗯,的确,CIL同样是面向对象的。   这意味着什么呢?那就是在CIL中你可以创建对象,调用对象的方法,访问对象的成员。而这里需要注意的就是对方法的调用。回到上表中的右上角。对,就是对参数的操作部分。静态方法和实例方法是不同的哦~   ● 静态方法: ldarg.0么有被占用,所以参数从ldarg.0开始。   ● 实例方法: ldarg.0是被this占用的,也就是说实际上的参数是从ldarg.1开始的。   举个例子:假设你有一个类Murong中有一个静态方法Add(int a, int b),实现的内容就如同它的名字一样使两个数相加,所以需要2个参数。和一个实例方法TellName(string name),这个方法会告诉你传入的名字。

静态方法的处理:

  那么其中的静态方法Add的CIL代码如下:

  那么我们调用这个静态函数应该就是这样咯。

  对应的CIL代码为:

  可见CIL直接call了Murong的Add方法,而不需要一个Murong的实例。

实例方法的处理:

  Murong类中的实例方法TellName()的CIL代码如下:

Mono为何能跨平台?聊聊CIL(MSIL)(mono为什么不能用了)

  看到和静态方法的区别了吗?对,第一个参数对应的是ldarg.1中的参数1,而不是静态方法中的0。因为此时参数0相当于this,this是不用参与参数传递的。   那么我们再看看调用实例方法的C#代码和对应的CIL代码是如何的。

  到此,受制于篇幅所限(小匹夫不想写那么多字啊啊啊!)CIL是What的问题大致介绍一下。当然没有再拓展,以后小匹夫可能会再详细写一下这块。

How?

  记得语文老师说过,写作文最重要的一点是要首尾呼应。既然咱们开篇就提出了U3D为何能跨平台的问题,那么接近文章的结尾咱们就再来

提问:   Q:上面的Why部分,咱们知道了U3D能跨平台是因为存在着一个能通吃的中间语言CIL,这也是所谓跨平台的前提,但是为啥CIL能通吃各大平台呢?当然可以说CIL基于堆栈,跟你CPU怎么架构的没啥关系,但是感觉过于理论化、学术化,那还有没有通俗化、工程化的说法呢?   A:原因就是前面小匹夫提到过的,.Net运行时和Mono运行时。也就是说CIL语言其实是运行在虚拟机中的,具体到咱们的U3D也就是mono的运行时了,换言之mono运行的其实CIL语言,CIL也并非真正的在本地运行,而是在mono运行时中运行的,运行在本地的是被编译后生成的原生代码。当然看官博的文章,他们似乎也在开发自己的“mono”,也就是被称为脚本的未来的IL2Cpp,这种类似运行时的功能是将IL再编译成c++,再由c++编译成原生代码,据说效率提升很可观,小匹夫也是蛮期待的。   这里为了“实现跨平台式的演示”,小匹夫用mac给各位做个测试好啦:

从C#到CIL

  新建一个cs文件,然后使用mono来运行。这个cs文件内容如下:                  然后咱们直接在命令行中运行这个cs文件试试~            说的很清楚,文件没有包含一个CIL映像。可见mono是不能直接运行cs文件的。假如我们把它编译成CIL呢?那么我们用mono带的mcs来编译小匹夫的Test.cs文件。

  生成了什么呢?如图:              好像没见有叫.IL的文件生成啊?反而好像多了一个.exe文件?可是没听说Mac能运行exe文件呀?可为啥又生成了.exe呢?各位看官可能要说,小匹夫你是不是拿windows截图P的啊?嘿嘿,小匹夫可不敢。辣么真相其实就是这个exe并不是让Mac来运行的,而是留给mono运行时来运行的,换言之这个文件的可执行代码形式是CIL的位元码形态。到此,我们完成了从C#到CIL的过程。接下来就让我们运行下刚刚的成果好啦。

               结果是输出了一个大大的“Hi”。这里,就引出了下一个部分。

从CIL到Native Code

  这个“HI”可是在小匹夫的MAC终端上出现的呀,那么就证明这个C#写的代码在MAC上运行的还挺“嗨”。   为啥呢?为啥C#写的代码能跑在MAC上呢?这就不得不提从CIL如何到本机原生代码的过程了。Mono提供了两种编译方式,就是我们经常能看到的:JIT(Just-in-Time compilation,即时编译)和AOT(Ahead-of-Time,提前编译或静态编译)。这两种方式都是将CIL进一步编译成平台的原生代码。这也是实现跨平台的最后一步。下面就分头介绍一下。

JIT即时编译

  从名字就能看的出来,即时编译,或者称之为动态编译,是在程序执行时才编译代码,解释一条语句执行一条语句,即将一条中间的托管的语句翻译成一条机器语句,然后执行这条机器语句。但同时也会将编译过的代码进行缓存,而不是每一次都进行编译。所以可以说它是静态编译和解释器的结合体。不过你想想机器既要处理代码的逻辑,同时还要进行编译的工作,所以其运行时的效率肯定是受到影响的。因此,Mono会有一部分代码通过AOT静态编译,以降低在程序运行时JIT动态编译在效率上的问题。   不过一向严苛的IOS平台是不允许这种动态的编译方式的,这也是U3D官方无法给出热更新方案的一个原因。而Android平台恰恰相反,Dalvik虚拟机使用的就是JIT方案。

AOT静态编译

  其实Mono的AOT静态编译和JIT并非对立的。AOT同样使用了JIT来进行编译,只不过是被AOT编译的代码在程序运行之前就已经编译好了。当然还有一部分代码会通过JIT来进行动态编译。下面小匹夫就手动操作一下mono,让它进行一次AOT编译。

  从图中可以看到JIT time: ms,也就是说Mono的AOT模式其实会使用到JIT,同时我们看到了生成了一个适应小匹夫的MAC的动态库Test.exe.dylib,而在Linux生成就是.so(共享库)。   AOT编译出来的库,除了包括我们的代码之外,还有被缓存的元数据信息。所以我们甚至可以只编译元数据信息而不变异代码。例如这样:

  可见代码没有被包括进来。   那么简单总结一下AOT的过程:   ● 收集要被编译的方法   ● 使用JIT进行编译   ● 发射(Emitting)经JIT编译过的代码和其他信息   ● 直接生成文件或者调用本地汇编器或连接器进行处理之后生成文件。(例如上图中使用了小匹夫本地的gcc)

Full AOT

  当然上文也说了,IOS平台是禁止使用JIT的,可看样子Mono的AOT模式仍然会保留一部分代码会在程序运行时动态编译。所以为了破解这个问题,Mono提供了一个被称为Full AOT的模式。即预先对程序集中的所有CIL代码进行AOT编译生成一个本地代码映像,然后在运行时直接加载这个映像而不再使用JIT引擎。目前由于技术或实现上的原因在使用Full AOT时有一些限制,不过这里不再多说了。以后也还会更细的分析下AOT。

总结

  好啦,写到现在也已经到了凌晨3:分了。感觉写的内容也差不多了。那么对本文的主题U3D为何能跨平台以及CIL做个最终的总结陈词:   ● CIL是CLI标准定义的一种可读性较低的语言。   ● 以.NET或mono等实现CLI标准的运行环境为目标的语言要先编译成CIL,之后CIL会被编译,并且以位元码的形式存在(源代码—>中间语言的过程)。   ● 这种位元码运行在虚拟机中(.net mono的运行时)。   ● 这种位元码可以被进一步编译成不同平台的原生代码(中间语言—>原生代码的过程)。   ● 面向对象   ● 基于堆栈

附录

附录:操作码表

Unity3d中EventTrigger的封装 因为unity中新增的UGUI中的Button只有onClick事件,但如果想要丰富Button的点击事件,就要使用到EventTrigger,但是自带的用着不方便,所以就对他进行了封装

仿《文明》游戏制作日志3 一、关于正方形转化为六边形问题。延伸上次日志的方法,先生成一个矩形,然后通过简单地取中点和取四分点,构筑正六边形。然而遇到的问题是,

unity5.0安卓开发环境配置 之前弄过这破玩意,后来从装了个系统,一切还原,自然辛苦配置的安卓环境也没有了。我这人还有点强迫症,喜欢式化硬盘,后果你懂的,所以就只

标签: mono为什么不能用了

本文链接地址:https://www.jiuchutong.com/biancheng/377238.html 转载请保留说明!

上一篇:Android显示Unity视图(unityplayer安卓)

下一篇:Unity3d中EventTrigger的封装

  • 公司车保险费用高么
  • 待转销项税额是几级科目
  • 所得税 报表
  • 计提无形资产摊销额计入什么科目
  • 应交税费为什么记借方
  • 管理费用借贷方都有,如何结转
  • 应收账款周转率正常值范围
  • 索赔费用项目
  • 建筑企业预收款开具不征税发票为什么要预缴
  • 建筑企业发生分包业务如何确认收入
  • 福利企业的税收优惠政策
  • 二次股权转让的股权原值确认
  • 物业公司收取电损费合法吗
  • 对外投资借款费用计入
  • 公司租赁的车辆发生的费用都可以报销吗?
  • 固定资产报废会议记录怎么写
  • 用于研发的设备会计分录
  • 用于在建工程的原材料进项税额可以抵扣吗
  • 票据贴现无手续怎么处理
  • 双倍余额递减法考虑净残值吗
  • 房屋征收服务中心是干什么的
  • 购买方开具红字信息表流程
  • 企业出租房屋交什么税?
  • 快消品应收账款风险策划方案
  • 企业购买黄金如何处理
  • 两免三减半适用范围
  • 结转成本是否要等货物卖出后
  • linux查杀webshell
  • com2us密码找回
  • 固定成本变动成本混合成本的分类
  • 设备的折旧率是什么意思
  • 新会计准则的科目
  • 喜加一平台
  • 增值税专用发票上注明的价款含税吗
  • u盘突然被写保护是坏了吗
  • vue打包注意事项
  • 担保损失怎么处理好
  • 社会保险个人部分计入什么科目
  • php 面向对象
  • php数组函数面试题
  • vue3 拖拽
  • css中清除浮动
  • dede转zblog
  • chkdsk.exe/f命令
  • phpcms视频教程
  • 从汽车生产到销售有哪些过程
  • 出租改自用房产税
  • 注册公司冠名省需要多少注册资金
  • 调整汇兑损益的摘要怎么写?
  • 发票开具就能做账了吗?
  • 固定资产转让损失怎么算
  • 其他应付款结转收入的条件
  • 在职职工在单位应享受哪些待遇
  • 存货盘盈的账务处理入什么费用
  • 租赁存在的原因有哪些
  • 车船税税金及附加
  • 股权转让如何支付利润
  • 代理出口业务会计分录
  • 工业企业销售商品分录
  • SQL Server 2012 sa用户登录错误18456的解决方法
  • 怎么卸载xp系统安装win7系统
  • windows server 2003 密钥
  • vmware虚拟化解决方案
  • cmd命令怎么进入d盘文件夹
  • 资源管理器 windows
  • win10周年更新版是什么意思
  • centos用户添加到组
  • Win7登录密码
  • win8更改电脑设置在哪
  • windows8应用商店在哪
  • w7系统序列号怎么查
  • 深入理解rcu
  • js定义数字
  • 尽有可能的拼音
  • androidsdk的计算机
  • 税务要求实名认证
  • 企业登录初始密码
  • 江西省税务局官网查询系统
  • 分公司的总公司
  • 2020北京户口指标数量
  • 免责声明:网站部分图片文字素材来源于网络,如有侵权,请及时告知,我们会第一时间删除,谢谢! 邮箱:opceo@qq.com

    鄂ICP备2023003026号

    网站地图: 企业信息 工商信息 财税知识 网络常识 编程技术

    友情链接: 武汉网站建设