zoukankan      html  css  js  c++  java
  • C#性能理解以及CTS

    前言   《CLR via C#》——作者Jeffrey Richter。本书是.NET 界的经典之作,集万千荣耀于一身。最近开始看这本书,有点相见恨晚的感觉。中文翻译版早就上市了,但是为了更加直接地领悟书中的深意,还是选择英文电子版 (环保,"免费")。学习的过程做点笔记与大家分享,我也建议大家看英文原版(这样能够更获取更直接的信息,而且英文书籍普遍讲的都非常细致,非常利于自学)。

    关于C#/.NET性能

    在上次的例子里面,第二次执行Console.WriteLine()方法时,会完全跳过JITCompiler编译。因为第一次已经完全编译为了本地CPU指令并且返回了指令在内容里的入口地址,所以这一次会直接跳转到该方法的内存地址处执行代码,当然也会比第一次的性能要高。

    C#性能较之C/C++低在哪?

    在托管环境中,完成代码的编译会经历两个过程:

    1.源码首先被编译为IL代码

    2.执行代码时,IL会经历第二次编译为本地CPU指令,这个过程需要分配更多的内存和占用CPU资源。

    怎么客观地看待这个部分?

    1.首先必须承认二次编译的确损害了性能,并且分配了动态内存。分配动态内存意味着当程序终止时,编译的代码会被丢弃。再次运行程序或启动两个程序的实例,JIT编译器会再次将IL编译为本地CPU指令。非托管语言(C/C++)编译器会针对具体的CPU平台编译,调用时直接执行。

    2.对大多数程序而言,都会反复多次调用同一个方法。这些方法仅仅在第一次被调用时会进行二次编译,从而降低了性能。其实,可能有时在一个方法里面执行的时间比调用一个方法的时间长的多,所以即使是第一次调用需要消耗性能,可能相对于在整个方法执行的时间来说只是占用了一小部分比例。

    3.微软做了很多优化的工作来保证将性能的损耗降到最低。例如,在IL编译为本地CPU指令时,编译器能够比非托管编译器知道更多关于执行环境的信息。下面列举托管编译器胜过非托管编译器的几个方面:

    ①JIT编译器能够判定程序是否运行在Intel Pentium 4 CPU上,并且利用Pentium 4CPU提供的任何专用的指令的优势来生成本地CPU指令。通常,非托管程序会针对最普遍CPU情况编译,从而避免使用CPU提供的专用指令来提升性能。

    ②JIT编译器能够确定当一个测试在机器上运行时始终为false的情形。例如:if(numberOfCPUs>1){...}.如果宿主机器只有一个CPU,那么这段代码能够让JIT编译器不生成任何CPU指令。这种情形能够让本地CPU指令得到一些微调,从而让代码更小执行更快。

    认识IL

    IL是基于栈的,所有IL指令通过push操作到执行栈,并且通过pop操作将结果出栈。由于IL没有提供操作寄存器的指令,很容易让人们创造出针对CLR的语言和编译器。IL指令也是无类型的。例如,IL提供的Add指令(将最后两个操作push到栈)并没有两个针对32位和64位的Add指令。当Add指令执行时,它会决定栈上操作的类型并执行适合的操作。

    IL的优点

    1.从底层的CPU抽象出来

    2.健壮性和安全性:IL编译为本地CPU指令时,CLR执行了一个审核过程,检查高级IL代码确保它们是安全的,例如方法被调用时,参数的个数和类型是否正确;如果有返回值,那么检查方法是否有return语句等等。托管模块的元数据包含了审核过程需要的所有方法和类型信息。在Windows中,每一个进程有它自己的虚拟地址空间,这很有必要,因为你不能信任一个程序的代码。程序完全有可能从一个未验证的内存地址读取或写入,放到独立的地址空间增强了程序的健壮性和稳定性。而且这样可以在一个Windows虚拟地址空间运行多个托管程序。

    3.由于进程会占用Windows的资源,进程越多占用的越多。多个托管程序可以运行在一个操作系统进程从而提升了性能。

    CLR怎么实现在一个进程运行多个托管程序?

    每一个托管程序在一个应用程序域执行。默认情况下,每一个托管的exe文件运行具有一个应用程序域的独立地址空间,CLR的宿主进程能够运行多个应用程序域。

    了解不安全代码

    微软C#编译器默认生成的是安全代码——代码是经过安全审核的。C#编译器也允许开发这写不安全的代码——直接操作内存地址以及在内存中的字节。这个功能在我们与非托管代码交互时非常有用。所有方法在包含不安全代码时,必须标记unsafe。当JIT编译器试图编译一段不安全代码时,它会检查该代码是否通过设置System.Security.Permissions.SecurityPermissionFlag’s SkipVerification标志授权。如果设置了该标志位,CLR会信任该段代码并期望直接地址和字节操作不会引起任何损害。如果没有设置会抛异常。

    认识公共类型系统CTS

    1.CTS:描述类型的定义及行为。

    2.CTS规范声明了一个类型能够包含0个或多个成员:字段,方法,属性,事件。

    3.CTS也规定类型及其成员的可访问性,下面列举出来:

    Private:同一个类里面可以访问

    Family:能够被派生类里面的成员访问,而不用考虑是否在同一个程序集里里面。C#里面用Protected修饰

    Family and assembly:能够被在同一个程序集里面的派生类成员访问。C#及VB没有提供该访问控制修饰,IL汇编语言是可以的。

    Assembly:同一个程序集可以访问。C#里面用internal修饰

    Family or assembly:能够被派生类访问(不管是否在同一个程序集),也能够被同一个程序集的任何类型访问(不用考虑是否是派生类)。C#用protected internal修饰

    public:没有限制。

    4.CTS定义了类型继承的规则,虚方法,对象生命周期等等。

    5.CTS规定所有类型必须从System.Object继承。Object是定义在System命名空间下的,是所有类型的根,这样可以保证所有的类型具有一个最小化的行为集合。System.Object定义下面几种行为:①两个实例的比较   ②获取实例的哈希代码   ③查询实例的真实类型   ④执行类型的浅复制  ⑤获取实例对象当前状态的字符串表示

    欢迎路过的朋友留言,谢谢!


    在技术的海洋,做个渔夫;不是牛人,同为凡客

    分类: CLR
  • 相关阅读:
    Vue移动端调用高德获取当前定位城市
    var,let,const三者的区别
    JVM学习与总结一
    五层网络模型整理
    功能强大的CFR反编译工具
    jad 反编译 jar文件、批量、单个class文件,秒懂!
    [ERROR] 2020-08-03 10:18:11 [RMI TCP Connection(3)-127.0.0.1] org.springframework.web.context.ContextLoader.initWebApplicationContext(ContextLoader.java:350) Context initialization failed
    TortoiseSVN的bin目录下没有 svn.exe 问题;Error running 'tomcat8.0.47': Unable to open debugger port (127.0.0.1:57422): java.net.SocketException "socket closed";端口被占用问题
    显示数据时,将同列不同行的数据合并到其中一行的sql
    java.lang.IllegalArgumentException: ServletContext must not be null
  • 原文地址:https://www.cnblogs.com/Leo_wl/p/2585150.html
Copyright © 2011-2022 走看看