运行机制---进阶编程篇(一)

       我已经假定你安装了宇宙第一IDE:visual studio 2017版本了,一个好的IDE会让你在敲代码的时候获得一个好心情,想想多年以前,很多人还是用VC++6.0,估计在现在,还是有一部分的人在使用,那个IDE用起来非常的不顺手,连提示错误都没有,很多时候我们只是手贱打错了个字,为了查错那个辛苦啊。扯远了,反正我没用过VC++6.0,如果你开始使用,推荐也是从最新版开始吧。

      我们开始新建第一个winform项目,点击新建项目后就弹出来下面的对话框:

      

新建完成后,就是如下的界面了:

      

这时候点击F5运行,然后就是这样:

      

      此处就出现了一个窗体,操作熟练的话,整个过程不到5秒就创建成功一个窗体了,一切都是那么的自然,自然的让我们以为创建窗口就应该是这个样子的,简单,高效,不得不说,这也是微软这么多年来努力的目标之一,就是让大家在开发程序的时候,可以尽可能的快速,便捷式操作,傻瓜式操作,使得编程的门槛大幅度的降低,上述的操作交给一个完全的新手时,几分钟就教会了。然后教教他怎么显示文本,怎么改变文本,估计也是几分钟的事情,就可以写一个简单的程序了。微软这么做的结果就是降低编程门槛,越来越多的人来学习C#,但也导致了水平普遍偏低的结果,就比如创建这个窗口,你在创建一百个这样的窗口,水平也没有提升再多了,因为这简单的几部它就是没什么技术含量的。

      终于进入到了本文的重点了,讲解我们用C#编写的程序的运行机制,这部分的内容对于新人来讲确实挺难理解的,我一开始学习的时候简直就是看天书一样的,所以我会尽量的将我所知道的用平实的语言讲出来,这部分内容对于理解C#来说至关重要,也是进阶的必经之路。所以我先大概说明一下运行机制,再分部完成。

  就比如上面生成的exe程序,它到底是什么玩意,我想很多人都会疑问,刚学习C#的我也是这样。

  1. 我们首先在VS中写了很多的代码,点击生成或是调试的时候,IDE使用了C#编译器将我们写的所有的代码编译成了一种中间语言IL语言,写入到了生成的exe中。
  2. 可以想想看exe包含了什么东西,我们在上述的项目中定义了新的类Form1,那么这些类系统又不提供,所以肯定会把类写入到exe中,只要是自定义的类肯定会写入进去。
  3. 我们可以猜测exe文件应该还有个文件头,来标识这是一个可执行的Win32程序,我们在创建项目时可以选择.NET版本,应该还包含了环境版本

  到这里我们的猜测已经非常的接近事实的情况了, 所以当我们点击exe程序的时候,windows到底干了什么东西。

  

  首先windows会检查exe文件的文件头,检查程序类型是不是PE32文件头还是PE32+文件头的,这个文件头要求程序的运行环境,是不是32位,还是64位的,如果和操作系统不匹配,则不会运行,检查.NET 的版本号。

  windows检查完exe后,检查合格后,接下来就要创建程序需要运行的进程空间了,在进程的地址空间加载MSCorEE.dll(一个.NET framework自带的链接库,可以在安装目录找到)。

  MSCorEE.dll的用处非常大,进程的主线程会调用组件的方法来初始化运行的CLR,然后加载exe的数据(就是中间语言IL代码,包含了所有的类型说明和数据,即使加载了,还是IL代码,还不不能直接运行的,如果你的exe还引用了其他的dll,那么所有的关联的dll都会加载进来)。

  然后MSCorEE.dll组件调用Main方法,这个和我们大学学的C语言是一致的,但是问题出现了,我们上面说过这时候CLR加载的还是IL代码,IL代码又不能直接运行,所以CLR内部的JITCompiler方法就出来干活了,工作是将IL代码编译成本机的CPU指令,这样操作后Main方法才可以真正的运行,如果Main方法调用了其他方法(这不是废话么),那么JITCompiler又出来工作了,如果每次调用方法,都要重新编译一次,那么应用程序的性能就非常差了,所以CLR使用了缓存的机制,所有的方法只有在第一次调用的时候存在一点性能损耗,以后调用就直接使用了本地指令。

  绕着这么多的弯路,终于窗体运行了,展示给你看了,汗颜-------

  这里肯定会有小伙伴跳出来说,这么搞累不累啊,我也想说,确实挺累的,为了运行一个程序,绕了一个大弯,我还记得我在大学的时候学的单片机,虽然我使用C语言来写程序的,但是编译器直接编译成了汇编写入ROM中,然后指针就可以直接调用程序了,你看,多么的简单明了。相比较而言,我们就不能用C#写的程序生成windows直接可以运行的程序吗?或者说直接生成IL的exe,再编译一次直接生成机器语言多好,运行效率会高很多。

  要想回答这个问题,我们需要探究一下IL语言为什么会产生,大致就能回答上述的问题了,说到IL的产生,又不得不说.NET的生成历史,当年微软看到JAVA发展如你中天时,心里也痒痒了,也想做一个新的语言,运行在虚拟机上,这样的程序和平台无关,可以实现程序的方便移植,虽然后来做着做着还是绑定了windows系统,但是至少和windows版本没有了太大的关系,比如上述的exe程序,是基于.NET 4.5的,只要安装了.NET 4.5的话就可以很好的支持,不必为了针对哪个系统,哪个CPU架构来区别对待。事实上基于CLR的IL可以实现的功能非常的强大,拥有完整的面向对象的机制,提供了抛出异常和处理模型,只是在C#层面就只能实现部分的CLR功能,也就是说,如果CLR不支持的功能,在C#层面就肯定不支持了。

  如果直接生成了基于机器指令的exe程序,事实上微软完全可以做到,但是这也丧失了动态性能,JITCompiler在即时编译指令时,会根据当前的cpu来优化本地指令,为特定cpu生成的程序有可能会在其他电脑无法运行,这就失去了程序的健壮性,谁都不会希望开发出这种程序吧。

  关于性能损耗,微软早就意识到这个问题了,花了非常大的人力物力来优化JIT的性能损耗,在我的经验中,性能非常的高效,已经满足绝大多数的场景。

  到此处为此,其实已经说的非常完整了,需要多读几遍,才能比较好的理解,也可以自己去查查看IL代码是什么样子的,相信还有很大的收获的。

原文地址:https://www.cnblogs.com/dathlin/p/7213793.html