C#运行流程
①C#编译器先将源代码编译成IL文件和元数据,并连同其他资源文件合并成程序集,程序集的可执行文件存储在磁盘上,通常具有的扩展名为 .exe 或 .dll(编译阶段)。
②程序集合并完成后,若程序集可执行,在Main()方法执行之前,window开启一个进程,并再加载MSCOREE.DLL,然后进程的主线程会调用MSCOREE.DLL中的方法初始化CLR(公共语言运行库),CLR中JIT(即时编译)会把IL语言转换为cpu指令(也称及其指令),并以文件方式存储在硬盘上,操作系统将文件从硬盘读入内存,CPU从内存中取出指令执行(运行阶段)。
中间语言MSIL
开发者编写的代码编译后,不依赖于操作系统和特定的CPU架构机器指令,而是依赖于一种中间的,在各个操作系统上都能执行的代码。
这种代码Java里面叫做ByteCode,.NET里面我们称之为MSIL指令。
不管是Java的字节码还是.NET的MSIL指令仍然需要最终被翻译成CPU能够执行的机器指令。这个功能是由一个运行在特定操作系统上的软件来完成,这个软件我们称之为“虚拟机”。
C#内存结构
栈内存:用于存储值类型数据
SOH堆,小对象堆,存储小的引用类型的实例对象
LOH堆,大对象堆,存储打的引用类型的实例对象,主要是85000字节以上的对象。
C#中垃圾回收GC
本部分总结来自我对《CLR via C#》一书的笔记
https://www.cnblogs.com/errornull/p/10049675.html
GC发生的流程
在托管堆值,刚刚创建的对象被称为第0代,CLR会给第0代的对象初始化预算容量,如果超过了容量,就会执行垃圾回收,而CLR使用引用跟踪法来实现垃圾回收。
首先将线程暂停,因为垃圾回收会使对象位置变化,需要更新对象地址。
然后将所有对象标记为删除,栈上的引用类型变量被称为根,根据根列表检查对象,标记的对象是可达的,并构建一个可达对象的图。
标记完成后就开始释放内存,幸存的对象被归为第1代,并将对象压缩到成占用连续内存。
每代都有预算容量不断循环对第0代进行垃圾回收,如果第1代的预算容量也超过了就对第1代和第0代都进行垃圾回收,然后第1代成为第2代,第0代成为第1代,其中CLR只有三代。
GC发生的时机
①代码显式调用Syste.GC的静态Collect方法
②Windows报告低内存情况
③CLR正在写卸载AppDomain
④CLR正在关闭,进程终止
⑤每一代的预算容量被超过。