• 学习CLR Via C#的一些体会


    一个.net程序的创建过程

    1.创建helloworld.cs;
    using System;
    void main()
    {
        string str="helloworld";

     a a1=new a();

        Console.WriteLine(str);
    }

    class a

    {}

    2.csc \o:helloworld.exe helloworld.cs ,编译为一个exe文件,也就是一个托管模块,在这一步发生的事情很多,
    编译器将c#代码编译为IL代码,组成一个标准的PE文件,就是托管模块,
    这个托管模块包括PE32+头、CLR头、IL代码和元数据,
    PE32+头:标准的PE头,但是其中会包括一个清单(manifest)的数据块,描述了构成程序集的文件
    CLR头包括所要求的CLR版本,一些标志、入口方法(main)的methoddef元数据标志,以及模块的元数据、资源、强名称等数据项的位置和大小;
    IL代码:运行时由CLR编译成本地CPU指令
    元数据:两种类型的表:一种类型描述源代码中定义的类型和成员,另一种类型描述源代码中引用的类型和成员
    3,执行helloworld.exe文件
    首先,windows系统检查exe的PE头,判断是创建32位/64位进程,然后创建进程,分配进程空间
    然后,在进程空间中加载MSCorEE.dll,
    第三,进程的主线程执行MSCorEE.dll内部定义的一个方法,这个方法初始化CLR,加载程序集,然后调用其入口方法(main)。(程序集是一个抽象概念,在这里指的就是helloworld.exe这个托管模块,因为程序集中只有这一个模块,ps:还记得吗,模块中有PE32+头,CLR对程序集处理时,会全部忽略PE头,呵呵,PE头在经过windows系统检查以及创建进程后就被抛弃了)。
    第四,IL代码开始执行了。记住IL代码是由JIT编译器即时编译后运行的

    4,执行IL代码的过程:

    CLR查找元数据,确保所有所需的程序集,如MSCORLIB.DLL等程序集都加载到AppDomain中
    这个进程中只有一个线程,就是主线程,这个线程被创建时,会分配到1M的堆栈,这个堆栈用于存储方法的局部变量和实参,这里,string str="helloworld";str是局部变量,所以入栈,然后有Console类,这个类来自于system命名空间,那么这里JIT会在托管堆中创建Console的类型对象,其字段包括类型对象指针、同步块索引(有一位用于标示可达状态)和静态字段,然后调用类型对象的静态方法WriteLine。

    PS:

    *new一个对象,这里没有写new语句,在创建对象时,值类型放入堆栈中,引用类型放入托管堆,值类型不会发生垃圾回收,垃圾回收只发生在托管堆。
    *回收资源
    垃圾收集使用代的机制,0代对象是最近分配的对象,1代是0代回收后存活的对象,2代是1代回收后存活的对象
    *垃圾收集的时机:
    1,0代对象充满;
    2,调用GC.COLLECT()
    3,卸载AppDomain
    4,windows报告内存不足
    5,CLR关闭
    *垃圾收集的过程包括:
    1,标记阶段,遍历线程堆栈检查所有根,并遍历所有可达对象
    2,压缩阶段,压缩时所有线程必须挂起,垃圾收集器遍历堆并搬迁非垃圾对象到哪些连续的区块以压缩托管堆,然后,垃圾收集器还必须遍历所有根,修改他们使其指向这些对象的新的位置

    *什么是终结操作(Finalize)

    ~aa();就是对象的终结操作,用于释放非托管资源。

    *对于终结操作的特殊处理:
    1,当new一个对象时,new操作符在托管堆上分配空间,如果类型定义了Finalize方法,那么在该类型的实例构造器调用之前,将一个指向这个对象的指针放入“终结列表”,当垃圾收集时,如果这个对象不可达,那么将垃圾收集器不会马上回收这个对象的空间,而是将终结列表上的指针放入“终结可达列表”,执行回收时,垃圾收集器将托管堆上的其它对象回收,这个对象不会回收。一个特殊的线程会清空“终结可达列表”,同时执行这个对象的Finalize方法。下一次垃圾收集时,这个对象因为不可达,垃圾收集器回收托管堆上的这个对象的空间。实际上,因为对象的代会提升,所以释放一个对象占用的内存可能的收集次数会超过两次。

    CLR怎样调用静态方法:定位在堆中的类型对象,然后JIT编译这个类型对象的静态方法,然后执行;
    怎样调用非虚实例方法:根据变量的类型找到在堆中的类型对象,查看是否有该方法,没有则向上回溯查找,然后编译实例方法,执行
    怎样调用虚实例方法:根据变量的地址找到发出调用的对象,然后检查这个对象的内部类型指针成员,这个成员引用了对象的实际类型,然后编译实际类型的方法,执行
    所有的类型对象都指向一个Type类型对象,而这个Type类型对象则指向本身。呵呵,具体看书

  • 相关阅读:
    正则:匹配以某字符串结尾或不以某字符串结尾的字符串或包含某字符并且不以某字符串结尾的字符串
    【访问网络资源出错】不允许一个用户使用一个以上用户名与服务器或共享资源的多重连接
    运行 TSQL 调试器之前配置防火墙规则
    SQL Server的照合顺序的含义
    eclipse svn is already locked解决方案
    Python 如何提取邮件内容
    Python 一招搞定禅道提交bug
    Python 实现Excel自动化办公《下》
    Python 实现Excel自动化办公《中》
    Python 实现Excel自动化办公《上》
  • 原文地址:https://www.cnblogs.com/malingbo/p/2398142.html
Copyright © 2020-2023  润新知