一个对象设置为null VS的Dispose() [英] Setting an object to null vs Dispose()

查看:236
本文介绍了一个对象设置为null VS的Dispose()的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我的方式着迷的CLR和GC的工作(我正在努力扩大我在这方面的知识通过通过C#,乔恩斯基特的书/岗位读书CLR,更多)。

I am fascinated by the way the CLR and GC works (I'm working on expanding my knowledge on this by reading CLR via C#, Jon Skeet's books/posts, and more).

总之,什么是两种说法的区别:

Anyway, what is the difference between saying:

MyClass myclass = new MyClass();
myclass = null;

或者,通过MyClass的实现IDisposable和析构函数调用Dispose()?

Or, by making MyClass implement IDisposable and a destructor and calling Dispose()?

另外,如果我有一个using语句(如以下)一个code块,如果我一步通过code和退出using块,是设置的那么物体或当垃圾收集发生?会发生什么,如果我在使用块anyay调用Dispose()?

Also, if I have a code block with a using statement (eg below), if I step through the code and exit the using block, is the object disposed of then or when a garbage collection occurs? What would happen if I call Dispose() in the using block anyay?

using (MyDisposableObj mydispobj = new MyDisposableObj())
{

}

Stream类(如的BinaryWriter)有一个Finalize方法?我为什么要使用?

Stream classes (eg BinaryWriter) have a Finalize method? Why would I want to use that?

推荐答案

重要的是要分开处置垃圾收集。他们是完全不同的东西,有一个共同点,我会来一分钟。

It's important to separate disposal from garbage collection. They are completely separate things, with one point in common which I'll come to in a minute.

处置,垃圾收集和终结

Dispose, garbage collection and finalization

当你写一个使用语句,它只是一个语法技巧的try / finally块,这样处置是所谓即使在体内的code。使用语句引发异常。它的的意味着该对象被垃圾收集在块结束。

When you write a using statement, it's simply syntactic sugar for a try/finally block so that Dispose is called even if the code in the body of the using statement throws an exception. It doesn't mean that the object is garbage collected at the end of the block.

出售事项有关的非托管资源的(非内存资源)。这些可能是UI手柄,网络连接,文件句柄等。这些有限的资源,所以你一般都希望尽快可以释放他们。您应该实施的IDisposable 只要您输入拥有非托管资源,无论是直接(通常通过的IntPtr )或间接(通过流,例如,一个的SqlConnection 等)。

Disposal is about unmanaged resources (non-memory resources). These could be UI handles, network connections, file handles etc. These are limited resources, so you generally want to release them as soon as you can. You should implement IDisposable whenever your type "owns" an unmanaged resource, either directly (usually via an IntPtr) or indirectly (e.g. via a Stream, a SqlConnection etc).

垃圾收集本身只有内存 - 一个小的转折。垃圾收集器是能够找到其可以不再被引用的对象,和释放它们。它看起来并不垃圾所有的时间,虽然 - 它检测到它需要(例如,如果堆一代内存不足)

Garbage collection itself is only about memory - with one little twist. The garbage collector is able to find objects which can no longer be referenced, and free them. It doesn't look for garbage all the time though - only when it detects that it needs to (e.g. if one "generation" of the heap runs out of memory).

扭曲是的定稿的。垃圾收集器保持它不再访问对象的列表,但其中有一个终结(写成〜富()在C#中,有点混乱 - 他们是什么样C ++的析构函数)。它运行在这些对象的终结,以防万一,他们需要做额外的清理它们的内存被释放之前。

The twist is finalization. The garbage collector keeps a list of objects which are no longer reachable, but which have a finalizer (written as ~Foo() in C#, somewhat confusingly - they're nothing like C++ destructors). It runs the finalizers on these objects, just in case they need to do extra cleanup before their memory is freed.

终结几乎都是用来清理资源,在该类型的用户忘记在有条不紊地处理它的情况。所以,如果你打开​​一个的FileStream 却忘了叫处置关闭,终结会的最终的释放底层的文件为您处理。在一个精心编写的程序,终结应该几乎从来没有火在我看来。

Finalizers are almost always used to clean up resources in the case where the user of the type has forgotten to dispose of it in an orderly manner. So if you open a FileStream but forget to call Dispose or Close, the finalizer will eventually release the underlying file handle for you. In a well-written program, finalizers should almost never fire in my opinion.

的变量设置为

Setting a variable to null

这是一个变量设置为一小点 - 这是几乎从来没有要求为求垃圾收集。你可能有时会想这样做,如果它是一个成员变量,但在我的经验也很少对不再需要的对象的一部分。当它是一个局部变量时,JIT通常是足够聪明(在释放模式),要知道,当你不打算再次使用的参考。例如:

One small point on setting a variable to null - this is almost never required for the sake of garbage collection. You might sometimes want to do it if it's a member variable, although in my experience it's rare for "part" of an object to no longer be needed. When it's a local variable, the JIT is usually smart enough (in release mode) to know when you're not going to use a reference again. For example:

StringBuilder sb = new StringBuilder();
sb.Append("Foo");
string x = sb.ToString();

// The string and StringBuilder are already eligible
// for garbage collection here!
int y = 10;
DoSomething(y);

// These aren't helping at all!
x = null;
sb = null;

// Assume that x and sb aren't used here

在同一时间它的可以的是值得的局部变量设置为是,当你在一个循环中,部分分支机构循环需要使用可变的,但你知道你已经达到了上,你做的不是一个点。例如:

The one time where it may be worth setting a local variable to null is when you're in a loop, and some branches of the loop need to use the variable but you know you've reached a point at which you don't. For example:

SomeObject foo = new SomeObject();

for (int i=0; i < 100000; i++)
{
    if (i == 5)
    {
        foo.DoSomething();
        // We're not going to need it again, but the JIT
        // wouldn't spot that
        foo = null;
    }
    else
    {
        // Some other code 
    }
}

实施了IDisposable /终结

所以,应该自己的类型执行终结?几乎可以肯定不是。如果你只的间接的持有非托管资源(例如,您已经有了一个的FileStream 作为一个成员变量),然后加入自己的终结不会帮助:流将几乎肯定是符合垃圾收集,当你的对象,所以你可以依靠的FileStream 有一个终结器(如果需要的话 - 它可能是指别的东西,等)。如果你想持有非托管资源近直接,<一个href="http://msdn.microsoft.com/en-us/library/system.runtime.interopservices.safehandle.aspx"><$c$c>SafeHandle是你的朋友 - 这需要一点时间来与去,但它意味着你将<一href="http://www.bluebytesoftware.com/blog/2008/02/18/IDisposableFinalizationAndConcurrency.aspx">almost <一href="http://www.bluebytesoftware.com/blog/2005/12/27/NeverWriteAFinalizerAgainWellAlmostNever.aspx">never需要写一个终结一次。您应该通常只需要一个终结,如果你有一个资源真正直接处理(一个的IntPtr ),你应该移动到的SafeHandle 只要你能。 (有两个环节存在 - 读两种,理想。)

So, should your own types implement finalizers? Almost certainly not. If you only indirectly hold unmanaged resources (e.g. you've got a FileStream as a member variable) then adding your own finalizer won't help: the stream will almost certainly be eligible for garbage collection when your object is, so you can just rely on FileStream having a finalizer (if necessary - it may refer to something else, etc). If you want to hold an unmanaged resource "nearly" directly, SafeHandle is your friend - it takes a bit of time to get going with, but it means you'll almost never need to write a finalizer again. You should usually only need a finalizer if you have a really direct handle on a resource (an IntPtr) and you should look to move to SafeHandle as soon as you can. (There are two links there - read both, ideally.)

乔·达菲有一个<一个href="http://www.bluebytesoftware.com/blog/2005/04/08/DGUpdateDisposeFinalizationAndResourceManagement.aspx">very长套左右终结和IDisposable的准则(合写,有很多聪明人的),这是值得一读。这是值得的注意,如果你封你的类,它使生活变得更加简单:覆盖处置来调用一个新的虚拟的Dispose(布尔格局)当你的类是专为继承方法等只是相关的。

Joe Duffy has a very long set of guidelines around finalizers and IDisposable (co-written with lots of smart folk) which are worth reading. It's worth being aware that if you seal your classes, it makes life a lot easier: the pattern of overriding Dispose to call a new virtual Dispose(bool) method etc is only relevant when your class is designed for inheritance.

这已经有点絮絮叨叨的,但请你澄清,你想要些:)

This has been a bit of a ramble, but please ask for clarification where you'd like some :)

这篇关于一个对象设置为null VS的Dispose()的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆