转载 2011年03月16日 17:21:00

  • 8185

今天来谈谈C#的GC,也就是垃圾回收机制,非常的受教,总结如下
首先:谈谈托管,什么叫托管,我的理解就是托付C#运行环境帮我们去管理,在这个运行环境中可以帮助我们开辟内存和释放内存,开辟内存一般用new,内存是随机分配的,释放主要靠的是GC也就是垃圾回收机制。哪么有两个大问题 1.GC可以回收任何对象吗?2.GC什么时候来回收对象?回收那些对象?
对于第一个问题,GC可以回收任何对象吗?我是这样理解的,首先要明白一点,C#在强大也管不到非托管代码?哪么什么是非托管代码呢?比如stream(文件),connection(数据库连接),COM(组件)等等。。哪么这些对象是需要进行连接的,比如说我们写这样一句话FileStream fs = new FileStream(“d://a.txt”,FileMode.Open);实际上已经创建了和d://a.txt的连接,如果重复两次就会报错。哪么fs这个对象叫做非托管对象,也就是说C#

不能自动去释放和d://a.txt的连接。哪么对于非托管的代码怎么办,一会我来说。
    对于第二个问题,GC什么时候来回收,回收什么对象?我想后面的就不用我说了,当然是回收托管对象了。但是GC什么时候回收?是这样的:GC是随机的,没有人知道他什么时候来,哪么我写了一个例子,证明这一点
private void button1_Click(object sender, EventArgs e)

{

AA a = new AA();

AA b = new AA();

AA c = new AA();

AA d = new AA();

}

public class AA{}

在讲这个例子之前,要明白什么被称之为垃圾,垃圾就是一个内存区域,没有被任何引用指向,或者不再会被用到。哪么在第一次点击按钮的时候会生成4个对象,第二次点击按钮的时候也会生成4个对象,但是第一次生成的4个对象就已经是垃圾了,因为,第一次生成的4个对象随着button1_Click函数的结束而不会再被调用(或者说不能再被调用),哪么这个时候GC就会来回收吗?不是的!我说了GC是随机的,哪么你只管点你的,不一会GC就会来回收的(这里我们可以认为,内存中存在一定数量的垃圾之后,GC会来),要证明GC来过我们把AA类改成
public class AA

{

~AA()

{

MessageBox.Show("析构函数被执行了");

}

}

要明白,GC清理垃圾,实际上是调用析构函数,但是这些代码是托管代码(因为里面没有涉及到Steam,Connection等。。)所以在析构函数中,我们可以只写一个MsgBox来证明刚的想法;这个时候,运行你的程序,一直点击按钮,不一会就会出现一大堆的“析构函数被执行了”…

好了,然后让我们看看能不能改变GC这种为所欲为的天性,答案是可以的,我们可以通过调用GC.Collect();来强制GC进行垃圾回收,哪么button1_Click修改如下
private void button1_Click(object sender, EventArgs e)

{

AA a = new AA();

AA b = new AA();

AA c = new AA();

AA d = new AA();

GC.Collect();

}

哪么在点击第一次按钮的时候,生成四个对象,然后强制垃圾回收,这个时候,会回收吗?当然不会,因为,这四个对象还在执行中(方法还没结束),当点第二次按钮的时候,会出现四次"析构函数被执行了",这是在释放第一次点击按钮的四个对象,然后以后每次点击都会出现四次"析构函数被执行了",哪么最后一次的对象什么时候释放的,在关闭程序的时候释放(因为关闭程序要释放所有的内存)。

好了,现在来谈谈非托管代码,刚才说过,非托管代码不能由垃圾回收释放,我们把AA类改成如下
public class AA

{

FileStream fs = new FileStream("D://a.txt",FileMode.Open);

~AA()

{

MessageBox.Show("析构函数被执行了");

}

}

private void button1_Click(object sender, EventArgs e)

{

AA a = new AA();

}

如果是这样一种情况,哪么第二次点击的时候就会报错,原因是一个文件只能创建一个连接。哪么一定要释放掉第一个资源,才可以进行第二次的连接。哪么首先我们想到用GC.Collect(),来强制释放闲置的资源,修改代码如下:
private void button1_Click(object sender, EventArgs e)

{

GC.Collect();

AA a = new AA();

}

哪么可以看到,第二次点按钮的时候,确实出现了“析构函数被执行了“,但是程序仍然错了,原因前面我说过,因为Stream不是托管代码,所以C#不能帮我们回收,哪怎么办?
自己写一个Dispose方法;去释放我们的内存。代码如下:
public class AA:IDisposable

{

FileStream fs = new FileStream("D://a.txt",FileMode.Open);

~AA()

{

MessageBox.Show("析构函数被执行了");

}

#region IDisposable 成员

public void Dispose()

{

fs.Dispose();

MessageBox.Show("dispose执行了");

}

#endregion

}

好了,我们看到了,继承IDisposable接口以后会有一个Dispose方法(当然了,你不想继承也可以,但是接口给我们提供一种规则,你不愿意遵守这个规则,就永远无法融入整个团队,你的代码只有你一个人能看懂),好了闲话不说,这样一来我们的button1_Click改为private void button1_Click(object sender, EventArgs e)

{

AA a = new AA();

a.Dispose();

}

我们每次点击之后,都会发现执行了“dispose执行了”,在关闭程序的时候仍然执行了“析构函数被执行了”这意味了,GC还是工作了,哪么如果程序改为:
private void button1_Click(object sender, EventArgs e)

{

AA a = new AA();

a.Dispose();

GC.Collect();

}

每次都既有“dispose执行了又有”“析构函数被执行了”,这意味着GC又来捣乱了,哪么像这样包含Stream connection的对象,就不用GC来清理了,只需要我们加上最后一句话GC.SuppressFinalize(this)来告诉GC,让它不用再调用对象的析构函数中。那么改写后的AA的dispose方法如下:

public void Dispose()

{

fs.Dispose();

MessageBox.Show("dispose执行了");

GC.SuppressFinalize(this);
        }

本文下载自CSDN下载频道。

-------------------------------------------------------------------------------------------

----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

那.Net程序员在编程时应该怎么做,有没有一种既简单又有有效的方法来处理内在回收。愚人作以下建议,望各路高手不吝赐教:

1,对于不包涵或没有引用(直接或间接)非托管资源的类,特别是作用如同Struct的实体类,析构、终结器、Dispose均不采用。

2,对于包涵非托管资源的类,如数据库连接对象,文件句柄等,应继承IDispose接口,在Dispose方法中清理非托管对象。客户代码用using(…){}格式显示调用Dispose。如果继承了IDispose接口,Dispose方法就不要留空,这样没有任何意义。除了构造器,任何方法体留空都有害无益。

3,所有自定义类一般均不建议显式声明析构函数、Finalize方法。

C#或者.NET下的强制垃圾回收办法的更多相关文章

  1. flex 强制垃圾回收

    java和flash的垃圾回收都是一个比较热门的话题,今天我也用一个例子来测试下flash的强制垃圾回收.主要用到的而一个类是LocalConnection. 在Flash player的debug版 ...

  2. 【C# .Net GC】强制垃圾回收 和System GC

    属性 GC.MaxGeneration:获取系统当前支持的最大代数. 方法 GC.GetTotalMemory(bool forceFullCollection) 方法  true表示该方法先做垃圾收 ...

  3. as3中强制垃圾回收

    private function doClearance():void { // trace("clear"); try{ new LocalConnection().connec ...

  4. Java的垃圾回收机制:强制回收System.gc() Runtime.getTime().gc()

    垃圾回收 当引用类型的实体,如对象.数组等不再被任何变量引用的时候.这块占用的内存就成为了垃圾.JVM会根据自己的策略决定是回收内存 注意: 垃圾回收只回收内存中的对象,无法回收物理资源(数据库连接, ...

  5. .NET垃圾回收 – 原理浅析

    在开发.NET程序过程中,由于CLR中的垃圾回收(garbage collection)机制会管理已分配的对象,所以程序员就可以不用关注对象什么时候释放内存空间了.但是,了解垃圾回收机制还是很有必要的 ...

  6. .NET垃圾回收:非托管资源,IDispose和析构函数的结合

    http://blog.jobbole.com/85436/ 原文出处: 田小计划   欢迎分享原创到伯乐头条 前面一篇文章介绍了垃圾回收的基本工作原理,垃圾回收器并不是可以管理内存中的所有资源.对于 ...

  7. c# -- 对象销毁和垃圾回收

    有些对象需要显示地销毁代码来释放资源,比如打开的文件资源,锁,操作系统句柄和非托管对象.在.NET中,这就是所谓的对象销毁,它通过IDisposal接口来实现.不再使用的对象所占用的内存管理,必须在某 ...

  8. java 之 对象与垃圾回收

    1.垃圾回收机制只负责回收堆内存中的对象,不会回收任何物理资源(如数据库连接,网络IO等资源) 2.程序无法精确控制垃圾回收的运行,垃圾回收会在合适的时候运行.当对象永久的失去引用后,系统会在合适的时 ...

  9. .NET垃圾回收 – 非托管资源

    前面一篇文章介绍了垃圾回收的基本工作原理,垃圾回收器并不是可以管理内存中的所有资源.对于所有的托管资源都将有.NET垃圾回收机制来释放,但是,对于一些非托管资源,我们就需要自己编写代码来清理这类资源了 ...

随机推荐

  1. DPDK(mtcp)vs RDMA/ROCE

    0. 缠论: http://52investing.com/ 1. 简书.DPDK: http://www.jianshu.com/p/dcb6ccc83ea52. mTCP 和 DPDK 构造百万千 ...

  2. HBase写入性能改造(续)--MemStore、flush、compact参数调优及压缩卡的使用【转】

    首先续上篇测试:   经过上一篇文章中对代码及参数的修改,Hbase的写入性能在不开Hlog的情况下从3~4万提高到了11万左右. 本篇主要介绍参数调整的方法,在HDFS上加上压缩卡,最后能达到的写入 ...

  3. Android下基于SDL的位图渲染(二)理论篇

    理论篇 上一篇中介绍了如何将SDL2源码应用到Android渲染中,实际上SDL本身提供的android-project实现了基于android的c运行时环境,通过上面实践篇的介绍,就是完成这个环境搭 ...

  4. 让mysql查询强制走索引

    select * from slot_value_temp force index(idx_slot_type_id) WHERE slot_type_id = 'xxxxxx'; 不定期更新

  5. JS实现文本框和文本域获取焦点focus()时,光标在本文的末尾

    <!-- <input type="text" id="test1" name="test1" value="test ...

  6. 关于Python中深拷贝与浅拷贝的理解(一)---概念

    import copy a = [1, 2, 3, 4, ['a', 'b']] #原始对象 b = a #赋值,传对象的引用 c = copy.copy(a) #对象拷贝,浅拷贝 d = copy. ...

  7. Error Installing Tivoli Directory Server (TDS) for TNPMW1.3

    Install TDS with error "GLPCTL004E Failed to create database instance: 'ldapdb2'."   Error ...

  8. Memory Models And Namespaces

    分开编译 不要把变量和函数的定义放到头文件中. 可以分开编译源文件,然后将它们连接起来生成最终的可执行文件. 如果你只修改了一个文件,你可以只重新编译这个文件,之前编译过的其他文件就不需要再次编译了, ...

  9. logistic回归学习

    logistic回归是一种分类方法,用于两分类的问题,其基本思想为: 寻找合适的假设函数,即分类函数,用来预测输入数据的结果: 构造损失函数,用来表示预测的输出结果与训练数据中实际类别之间的偏差: 最 ...

  10. <花荣《至尊狐狸》中国股市精英最优套利战术>读书笔记

    书在这里 第一定律:博弈分析是一切实战操作的基础,资金的机会利润由主力投机状态决定,资金的风险承受度由投资标的价值底线锁定 第二定律:套利战术应是背景性的.主动性的.互动性的,是最安全最保守的.最明确 ...