CLR为开发者提供了一个非常让人激动的功能--垃圾回收。但是园子里关于垃圾回收的讨论,大多是讨论垃圾回收的原理,以及Dispose模式。但是垃圾回收在实际使用时,是不是可以达到其设计的目标,在开发过程中有没有需要注意的问题呢?本人也不是非常明确,这篇文章希望能达到抛砖引玉的效果,希望个人牛人能够给本人或同样存在疑惑的人一个清楚明确的答案。
什么是垃圾回收?就是说你在使用CLR的时候(不包含托管资源) ,只需要new一个对象使用。而不需要通过程序代码进行释放对象(以上是本人理解的垃圾回收的意义)。
托管资源 非托管资源
托管资源和非托管资源的区别通常会让开发者弄不清楚,到底什么是托管的,什么不是托管的。这里说一下自己的体会。如果你使用的Class是属于CLR的,不管它实际上使用的什么资源。CLR都会帮你进行垃圾回收。简单的比如一个List对象,你使用完成(变量脱离其作用域)就会被CLR自动回收。那么对于网上常说的数据连接,文件类呢?其实同样会在使用完成后被自动回收,但是因为此类资源很重要,而垃圾回收的时机不确定。所以很多教材上说此类资源需要在使用完成后及时释放(通过程序代码)。这里说明一点就是CLR的Class都会被自动回收,无论它实际控制的是托管资源还是非托管资源。
这里可以做一个简单的测试,一个WinForm项目,两个Button(button1, button2) ,点击事件如下。
private void button1_Click(object sender, EventArgs e)
{
FileStream file = new FileStream(@"c:\DisposeTest.txt", FileMode.Open);
}
private void button2_Click(object sender, EventArgs e)
{
GC.Collect();
}
连续点击button1,第二次就会报错,说明文件没有被释放。但是如果点击button1再点击button2再点击button1那么就不会报错了,因为button2垃圾回收将文件释放了。
那么哪些资源,对象是不能自动回收,必须通过程序代码释放的呢?简单的说你使用的Class, 组件不属于CLR。比如Win32API,Com组件等。使用上述类型的时候,如果分配了资源,那么一定要通过代码进行释放。还是文件打开的例子,如果是使用 Win32API打开文件,那么使用垃圾回收是没有办法释放资源的。所以一定要在代码中进行相关资源的释放。
垃圾回收在开发中的问题
托管资源,非托管资源已经说清楚了。垃圾回收的原理这里就不说了,网上很多文章介绍。下面我们说一下在实际开发过程中是不是可以完全相信垃圾回收,而不需要考虑对象的释放呢?或者哪些对象是需要及时释放的呢?本人主要是是从事WinForm开发。所以下面的讨论可能是以WinForm为背景。 一下是目前本人明确或者未明确的内容希望与大家讨论。
1)哪些资源需要及时释放?这个问题很明确了,数据库连接,文件,还有其他的大家补充吧。就想到这么多。
2)WinForm背景下,如果创建的Form被释放(Form = null)的时候,Form内的字段(比如,String, DataTable, 其他自定义类)是否会被自动释放(假设这些字段没有被其他的地方引用)。
3)因为从事的是数据库相关开发,自然用到最多的是ADO.Net,那么除了Connection,其他的对象是否需要及时释放,哪些对象是否需要及时释放(这里比较关心的是DataSet, DataTable)?
4)补充一点如果上述很多对象都需要及时释放,那么垃圾回收的意义是不是就一定程度的降低了呢?
以上是个人对垃圾回收的理解和疑问,希望大家能够一起讨论,最后能有明确的结论。