转载 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. localtime 和 localtime_r

    #include <cstdlib> #include <iostream> #include <time.h> #include <stdio.h> ...

  2. Spark SQL编程指南(Python)【转】

    转自:http://www.cnblogs.com/yurunmiao/p/4685310.html 前言   Spark SQL允许我们在Spark环境中使用SQL或者Hive SQL执行关系型查询 ...

  3. 前端复制粘贴clipBoard.js的使用

    <!DOCTYPE html> <html> <head> <title>ClipBoard.js使用:修改HTML</title> < ...

  4. GNU make简介

    引言 接触开源项目有一段时间了,对自动化编译工具一直很好奇.近期有时间正好整理下GNU make.后续可以深入了解下. 本文主要整理GNU make的学习的基本资料,同时简要介绍make的功能.语法. ...

  5. Python爬网——获取安卓手机统计数据

    [本文出自天外归云的博客园] 1. 在安卓网上对热门机型进行爬网,取前五十: # -*- coding: utf-8 -*- import requests,re from bs4 import Be ...

  6. 命令行todo神器taskwarrior使用简介

    简介 taskwarrior是一个命令行的任务管理神器,同时也有服务端,支持同步. 语法规则为 安装 Linux上可以直接软件包管理器安装 Window可以用cygwin Mac可以用homebrew ...

  7. Spring boot 报错 Unable to start EmbeddedWebApplicationContext due to missing EmbeddedServletContainerFactory bean.

    在实际开发中修改别人的代码,发现了这个报错,后来发现是因为pom.xml里面 只要将注释掉的部分注释掉就好了.

  8. JavaScript 中 类型转换

    转自 https://www.cnblogs.com/wuxiaoshang/p/5835627.html // 转换成字符型 var married = false; alert(married.t ...

  9. SpringMVC RedirectView的使用以及源码分析

    看一段普通的代码,我们访问controller中的一个方法后,重定向到另外一个controller或者视图. @RequestMapping(params="method=index&quo ...

  10. Android——MeasureSpec学习 - 解决ScrollView嵌套ListView和GridView冲突的方法

      原文地址:http://blog.csdn.net/yuhailong626/article/details/20639217   在自定义View和ViewGroup的时候,我们经常会遇到int ...