摘要:
GC全称Garbage Collection即我们通常所说的.NET的垃圾回收。这篇学习心得是我在阅读了MSDN的垃圾回收后的个人学习笔记
GC的出现,使我们.NET开发人员不再需要或者很少需要关心内存的管理。记得当初和C++程序员交流时,经常听到他们说程序反应好慢啊!查看源代码发现:原来忘记释放对象、引起内存泄漏。我当时就在想我用C#开发时,好像还没遇到过忘记释放对象,引发内存泄漏的事啊。用C#做开发也很少提到内存方面的问题(在一些对性能要求很高应用中也要考虑内存的手动管理)。为什么C#程序员很少考虑内存呢?
原来如此: C#程序开发是基于.NET Framwork框架的。“.NET Framework 的垃圾回收器管理应用程序的内存分配和释放。每次您使用 new 运算符创建对象时,运行库都从托管堆为该对象分配内存。只要托管堆中有地址空间可用,运行库就会继续为新对象分配空间。但是,内存不是无限大的。最终,垃圾回收器必须执行回收以释放一些内存。垃圾回收器优化引擎根据正在进行的分配情况确定执行回收的最佳时间。当垃圾回收器执行回收时,它检查托管堆中不再被应用程序使用的对象并执行必要的操作来回收它们占用的内存”(摘录MSDN)。
从上面文字我了解到了,垃圾回收器工作的一个大概过程:new一个对象申请一块内存,公共语言运行库接到申请就准备开始分配内存,就在这个时候垃圾回收器优化引擎走过来检查了,看了看申请单,再看了看托管堆里面空间的使用情况,发现托管堆空间不足以容纳此次申请的量,如是乎垃圾回收器找一个最佳时间开始清场。清完场,就开始去满足前面的申请。
垃圾回收器的工作过程
前面说到垃圾回收器,我开始有疑问了。垃圾回收器是从哪里来的?MSDN上面是这么说的:自动内存管理是公共语言运行库在托管执行过程过程中提供的服务之一。公共语言运行库的垃圾回收器为应用程序管理内存的分配和释放。我的理解是垃圾回收器的自动回收就是这里的自动内存管理服务。那么这个服务是怎么启动的呢?执行任何托管代码之前,宿主必须首先加载并初始化公共语言运行库,垃圾回收器我想就是在这个时候初始化的。
下面看看MSDN给出的垃圾回收器的自动管理内存的过程:
为了优化垃圾回收器的性能,托管堆分为三个生成级别:0、1 和 2。运行时的垃圾回收算法基于以下几个普遍原理,这些垃圾回收方案的原理已在计算机软件业通过实验得到了证实。首先,压缩托管堆的一部分内存要比压缩整个托管堆速度快。其次,较新的对象生存期较短,而较旧的对象生存期则较长。最后,较新的对象趋向于相互关联,并且大致同时由应用程序访问。
运行时的垃圾回收器将新对象存储在第 0 级托管堆中。在应用程序生存期的早期创建的对象如果未被回收,则被升级并存储在第 1 级和第 2 级托管堆中。因为压缩托管堆的一部分要比压缩整个托管堆速度快,所以此方案允许垃圾回收器在每次执行回收时释放特定级别的内存,而不是整个托管堆的内存。
实际上,垃圾回收器在第 0 级托管堆已满时执行回收。如果应用程序在第 0 级托管堆已满时尝试新建对象,垃圾回收器将会发现第 0 级托管堆中没有可分配给该对象的剩余地址空间。垃圾回收器执行回收,尝试为对象释放第 0 级托管堆中的地址空间。垃圾回收器从检查第 0 级托管堆中的对象(而不是托管堆中的所有对象)开始执行回收。这是最有效的途径,因为新对象的生存期往往较短,并且期望在执行回收时,应用程序不再使用第 0 级托管堆中的许多对象。另外,单独回收第 0 级托管堆通常可以回收足够的内存,这样,应用程序便可以继续创建新对象。
垃圾回收器执行第 0 级托管堆的回收后,会压缩可访问对象的内存,然后,垃圾回收器升级这些对象,并考虑第 1 级托管堆的这一部分。因为未被回收的对象往往具有较长的生存期,所以将它们升级至更高的级别很有意义。因此,垃圾回收器在每次执行第 0 级托管堆的回收时,不必重新检查第 1 级和第 2 级托管堆中的对象。
在执行第 0 级托管堆的首次回收并把可访问的对象升级至第 1 级托管堆后,垃圾回收器将考虑第 0 级托管堆的其余部分。它将继续为第 0 级托管堆中的新对象分配内存,直至第 0 级托管堆已满并需执行另一回收为止。这时,垃圾回收器的优化引擎会决定是否需要检查较旧的级别中的对象。例如,如果第 0 级托管堆的回收没有回收足够的内存,不能使应用程序成功完成创建新对象的尝试,垃圾回收器就会先执行第 1 级托管堆的回收,然后再执行第 0 级托管堆的回收。如果这样仍不能回收足够的内存,垃圾回收器将执行第 2、1 和 0 级托管堆的回收。每次回收后,垃圾回收器都会压缩第 0 级托管堆中的可访问对象并将它们升级至第 1 级托管堆。第 1 级托管堆中未被回收的对象将会升级至第 2 级托管堆。由于垃圾回收器只支持三个级别,因此第 2 级托管堆中未被回收的对象会继续保留在第 2 级托管堆中,直到在将来的回收中确定它们为无法访问为止。
前面这些都是自动内存管理,感觉是一切都是在幕后自动进行的,对象就那样在我们不知不觉中被清理掉了。给我们说声再见的机会都没?
Finalize 方法
托管对象的Finalize方法,在这里,你可以完成你被清理前的事情如:一些非托管对象的清理。。默认情况下,Finalize 方法不执行任何操作。如果您要让垃圾回收器在回收对象的内存之前对对象执行清理操作,您必须在类中重写 Finalize 方法。
强制回收:
有些时候,我们可能想主动进行内存回收,用GC.Collect()方法可以强制垃圾回收,以提前引发垃圾回收。
有关GC类的用法、垃圾回收器的更多内容查看MSDN