日期:2014-05-18  浏览次数:20830 次

有个小问题,需要再证实一下,关于.net垃圾回收
比如 object obj = new object();

  obj = otherobject;

在这里,obj原先指向的对象应该是会由系统自动回收的吧,也就是不需要显式的Dispose().

也就是说,我们可以任意new新的对象,不用的时候根本不需要去管它, 甚至于把它"忘掉",系统也会帮我们清理这些"垃圾". 是吗?

那么系统是如何判断某个对象现在已经没用了呢?

------解决方案--------------------
在C++中,对象所占的内存在程序结束运行之前一直被占用,在明确释放之前不能分配给其它对象;而在Java中,当没有对象引用指向原先分配给某个对象的内存时,该内存便成为垃圾。JVM的一个系统级线程会自动释放该内存块。垃圾收集意味着程序不再需要的对象是"无用信息",这些信息将被丢弃。当一个对象不再被引用的时候,内存回收它占领的空间,以便空间被后来的新对象使用。事实上,除了释放没用的对象,垃圾收集也可以清除内存记录碎片。由于创建对象和垃圾收集器释放丢弃对象所占的内存空间,内存会出现碎片。碎片是分配给对象的内存块之间的空闲内存洞。碎片整理将所占用的堆内存移到堆的一端,JVM将整理出的内存分配给新的对象。

以上是Java中的垃圾回收机制,.Net中也是这样。
------解决方案--------------------
好像是垃圾回收会定时检测,把没有引用的无效对象所占用的内存空间释放掉
------解决方案--------------------
引用 MSDN:
垃圾回收器跟踪并回收托管内存中分配的对象。垃圾回收器定期执行垃圾回收以回收分配给没有有效引用的对象的内存。当使用可用内存不能满足内存请求时,垃圾回收会自动进行。或者,应用程序可以使用 Collect 方法强制进行垃圾回收。

垃圾回收由以下步骤组成:

垃圾回收器搜索托管代码中引用的托管对象。

垃圾回收器尝试完成没有被引用的对象。

垃圾回收器释放没有被引用的对象并回收它们的内存。

在回收期间,如果垃圾回收器在托管代码中找到对某对象的一个或多个引用,则不会释放该对象。然而,垃圾回收器不识别非托管代码中对对象的引用,因此,除非明确禁止,否则它有可能释放非托管代码中以独占方式使用的对象。KeepAlive 方法提供一种机制,该机制可防止垃圾回收器回收在非托管代码中仍使用的对象。

除托管内存分配外,垃圾回收器的实现不维护有关一个对象所保持的资源(如文件句柄或数据库连接)的信息。当某个类型使用的非托管资源在回收该类型的实例之前必须释放时,该类型可以实现终结器。

多数情况下,终结器通过重写 Object..::.Finalize 方法来实现,但是,用 C# 或 C++ 编写的类型实现析构函数,由编译器将析构函数转换为对 Object..::.Finalize 的重写。多数情况下,如果某对象有终结器,则垃圾回收器会在释放该对象前调用其终结器。不过,垃圾回收器并不是在所有情况下都需要调用终结器;例如,当 SuppressFinalize 方法显式禁止调用终结器时,垃圾回收器就不需要调用终结器。此外,不需要垃圾回收器使用特定线程来完成对象,也不需要垃圾回收器为相互引用、但能以其他方式用于垃圾回收的对象保证终结器的调用顺序。

在资源必须在特定时间释放的方案中,类可以实现 IDisposable 接口,该接口包含执行资源管理和清理任务的 IDisposable..::.Dispose 方法。实现 Dispose 的类作为它们的类协定的一部分,必须指定类使用者是否需要及在什么时候调用该方法来清理对象。默认情况下,垃圾回收器并不调用 Dispose 方法,然而 Dispose 方法的实现可以调用 GC 类中的方法来自定义垃圾回收器的完成行为。

建议垃圾回收器使用代来支持对象老化,但这不是必需的。代是对象在内存中相对存现时期的度量单位。对象的代数或存在时期指示对象所属的代。较近创建的对象属于较新的代,比在应用程序生命周期中较早创建的对象的代数低。最近代中的对象位于零代中。

------解决方案--------------------
看这个文章能帮你更好理解垃圾回收:
CLR探索系列:GC 中的Card table和Brick Table(垃圾回收系列)
------解决方案--------------------
近期看了看有关.net的垃圾回收方面的知识,感觉有必要将这方面的资料总结一下,和广大网友分享一下
.net的垃圾回收,借鉴了java的垃圾回收机制。在以前的windows环境下,我们实例化一个对象后,我们经常会忘记
释放掉已经无用的内存,或者试图使用已经释放掉的内存,造成程序的崩溃。但是随着.net中的垃圾回收机制出现,
这种情况得到了大大的改善。
在.net中两种变量类型,一种是值类型,一种是引用类型,值类型所占的内存,存放在当前线程的栈上,垃圾回收
不负责回收这方面的内存,当前方法运行完毕后,内存会自动释放。引用类型所占的内存存放在托管堆上,
.net的垃圾回收就是负责回收这方面的内存资源。
在.net中提供三种模式来回收内存资源:dispose模式,finalize方法,close方法。
dispose提供了一种显示释放内存资源的方法。dispose调用方法是:要释放的资源对象.dispose
finalize方法是.net的内部的一个释放内存资源的方法。这个方法不对外公开,由垃圾回收器自己调用。
close和dispose其实一样,只不过有的对象没有提供dispose的方法,只提供了close方法,而close其实在
那个对象的类中,依然是调用了一个私有的dispose方法,而finalize其实也是调用一个不对外公开的dispose方法

那么既然.net在垃圾回收中了finalize方法,那么为什么还要提供dispose方法和close方法哪?这是因为finalize方法会释放
掉托管堆内存和非托管堆内存。而dispose只会释放掉非托管的内存资源,对于托管的内存资源它不会释放,只能由垃圾回收拉释放。
当我们打开一个数据库连接的时候(这是一个非托管内存资源),如果我们不手工释放这一部分资源,
等下一次垃圾回收调用finalize方法回收资源,那么可能会是很长的时间之后,所以要使用dispose这个方法。所以当我们使用
sqlconnection这个对象连接数据库后,调用sqlconnnection.dispose方法后,可以从数据库断开连接,但是sqlconnection这个
对象没有消亡,这个对象可以继续使用,直到下一次垃圾回收调用finalize方法回收资源。

我们再说一下close这个方法,我们上面提到过了,它起到的作用和dispose一样。只不过有的.net有的对象没有提供dispose方法,
而是用close代替,因为用close代替,比dispose显得更直观。
下面用一个例子说明finalize和dispose,close的区别
大家看下面的代码
dim a as string="1234"
dim fs as filestream("temp.txt",fileMode,create)
fs.write(a) ''''向文件写入内容
fs.dispose() '''显示关闭文件
fs.write(a) ''''抛出错误
因为当我们调用了dispose方法,我们只是关闭了temp.txt文件,fs对象是一个托管对象,他的资源没有被释放,依然可以使用,但是
temp.txt文件已经关闭,向一个已经关闭的文件写入内容,当然会出错。
大家再看下面的代码
dim a as string="1234"
dim fs as filestream("temp.txt",fileMode,create)