C#编译执行过程以及.net内存管理和垃圾回收

一、C#编译执行的过程

我们要和外国人交流,又不懂它们的语言,我们怎么办,无非就是先说出我们的语言,然后翻译出来,再给外国人听,这于代码的编写执行过程是一致的。下面简单介绍下C#代码的执行过程,并同时介绍IL、CLR、JIT等内容。

1.第一步是在类似visual studio2017这样的编译器上,按照规则写出C#代码,类似我们在说我们的母语。

2.第二步是编译器进行编译,产生dll或者exe文件,其中包含了metadata和IL,下面简单介绍下什么是metadata和IL。

metadata可以理解它是一份清单,包含了C#代码中的所有信息。

IL是中间语言,也有的地方叫MSIL(微软中间语言)

运行到这一步,相当于是在为翻译我们的母语做了准备,但是实际上还未产生真正的外国语。

3.第三步是在CLR下JIT进行编译产生了可在本机上运行的机器码。那么这里就需要重点解释一下什么是CLR和JIT。

CLR是公共语言运行时,正是由于该运行环境,使得不同语言编译产生的中间语言(IL)能够在不同操作系统中编译运行,例如32位操作系统,64位操作系统等,而且不同的操作系统中,CLR是不同的。由此可见,CLR,就是微软为.net产品构建的运行环境,与java的JVM类似,通俗的讲就是.net虚拟机,这意味着只要能将代码编译成这种特定的“中间语言”(MSIL),任何语言的产品都能运行在CLR上。这意味着.Net也很容易实现“跨平台”。CLR是.net系列产品运行的基础。

JIT是基于CLR的,JIT根据不同的CLR将中间语言(IL)根据metadata和exe或者dll,开始正式编译产生0101的机器码,同时JIT还会检测是否已经编译过,如果是则会直接重用机器码。

到这里C#语言的编译运行就完成了,由此可见,C#或者其他.net语言是需要先编译为中间代码,再在.net的CLR中安全运行,编译为可执行的机器码,所以C#一直自称是很安全的语言,因为背后有CLR为我们保驾护航,省去了许多麻烦,与之不同的是C/C++,它是直接编译成机器码没有中间代码的,所以在运行过程中需要由程序员自己管理内存等,这也就多了许多工作,对程序员的要求更高,但是同时它可能的功能会更多。

二、.net中的内存管理和垃圾回收

有了上面的铺垫,现在再说内存管理和垃圾回收会更容易理解。

我们知道,CLR是.net的运行基础,所以在IL编译为机器码的过程中,内存管理和垃圾回收工作都是又强大的CLR来完成的,虽然我们平时不需要深入去研究它是如何进行的,但是了解其原理有助于我们写出更加高效的代码。

一、第一步我们需要了解C#的数据类型与运行时的内存管理。C#数据类型可以分为值类型和引用类型,内存管理的空间可以分为线程栈和托管堆,线程栈是先进后出的数据结构,随着线程的进行而分配的;对象堆是进程中独立划分出来的一块内存。C#的引用类型存储在堆上,值类型存储在栈上,除非值类型所在的对象是引用类型。

二、第二步细致了解一下线程栈和托管堆的概念

1.值类型出现在线程栈,每次调用结束后,线程栈会自动释放,例如临时变量等。

2.引用类型出现在托管堆又叫CLR堆,是一段连续分配的内存,该内存空间是有限的,所以在不断产生引用类型时,空间不够就会产生GC。

三、第三步了解GC的原因和过程

1.什么是垃圾?垃圾是指完全访问不到的东西,例如临时变量或者已经赋值为null的引用类型等。

2.什么时候会发生GC?在new对象时,如果CLR分配的内存空间不够时,会发生GC;程序退出时会GC;或者手动GC,假如你的程序很久才执行一次,而且每次又使用的时间很短,就可以手动GC

3.是如何GC的?如果是在运行时GC,那么首先,CLR会遍历所有堆中的对象,标记所有有引用的对象,然后专门启动一个线程来进行垃圾回收清理内存,然后具体是如何清理的呢,CLR会清除没有标记的对象,挪动其余剩余对象,然后整齐摆放(因为内存是连续的一段内存空间),这个时候线程会停止,不允许操作内存。

注意:静态对象是不会垃圾回收的,而且静态对象所持有的引用也是不会被垃圾回收的。

发布了58 篇原创文章 · 获赞 7 · 访问量 3741

猜你喜欢

转载自blog.csdn.net/xy_learning/article/details/103062837