您是否需要处理对象并将其设置为null,或者当它们超出作用域时,垃圾收集器将清理它们?


当前回答

我同意这里常见的答案,是的,你应该处理,不,你通常不应该设置变量为null…但是我想指出dispose主要不是关于内存管理的。是的,它可以帮助内存管理(有时确实如此),但它的主要目的是让您确定地释放稀缺资源。

For example, if you open a hardware port (serial for example), a TCP/IP socket, a file (in exclusive access mode) or even a database connection you have now prevented any other code from using those items until they are released. Dispose generally releases these items (along with GDI and other "os" handles etc. which there are 1000's of available, but are still limited overall). If you don't call dipose on the owner object and explicitly release these resources, then try to open the same resource again in the future (or another program does) that open attempt will fail because your undisposed, uncollected object still has the item open. Of course, when the GC collects the item (if the Dispose pattern has been implemented correctly) the resource will get released... but you don't know when that will be, so you don't know when it's safe to re-open that resource. This is the primary issue Dispose works around. Of course, releasing these handles often releases memory too, and never releasing them may never release that memory... hence all the talk about memory leaks, or delays in memory clean up.

I have seen real world examples of this causing problems. For instance, I have seen ASP.Net web applications that eventually fail to connect to the database (albeit for short periods of time, or until the web server process is restarted) because the sql server 'connection pool is full'... i.e, so many connections have been created and not explicitly released in so short a period of time that no new connections can be created and many of the connections in the pool, although not active, are still referenced by undiposed and uncollected objects and so can't be reused. Correctly disposing the database connections where necessary ensures this problem doesn't happen (at least not unless you have very high concurrent access).

其他回答

当对象不再被使用并且垃圾回收器认为合适时,对象将被清理。有时,您可能需要将一个对象设置为null以使其超出作用域(例如您不再需要其值的静态字段),但总体而言,通常不需要将其设置为null。

关于处置对象,我同意@Andre的观点。如果对象是IDisposable的,那么在不再需要它时释放它是个好主意,特别是当对象使用非托管资源时。不处理非托管资源将导致内存泄漏。

一旦程序离开using语句的作用域,就可以使用using语句自动处理对象。

using (MyIDisposableObject obj = new MyIDisposableObject())
{
    // use the object here
} // the object is disposed here

其功能等价于:

MyIDisposableObject obj;
try
{
    obj = new MyIDisposableObject();
}
finally
{
    if (obj != null)
    {
        ((IDisposable)obj).Dispose();
    }
}

我同意这里常见的答案,是的,你应该处理,不,你通常不应该设置变量为null…但是我想指出dispose主要不是关于内存管理的。是的,它可以帮助内存管理(有时确实如此),但它的主要目的是让您确定地释放稀缺资源。

For example, if you open a hardware port (serial for example), a TCP/IP socket, a file (in exclusive access mode) or even a database connection you have now prevented any other code from using those items until they are released. Dispose generally releases these items (along with GDI and other "os" handles etc. which there are 1000's of available, but are still limited overall). If you don't call dipose on the owner object and explicitly release these resources, then try to open the same resource again in the future (or another program does) that open attempt will fail because your undisposed, uncollected object still has the item open. Of course, when the GC collects the item (if the Dispose pattern has been implemented correctly) the resource will get released... but you don't know when that will be, so you don't know when it's safe to re-open that resource. This is the primary issue Dispose works around. Of course, releasing these handles often releases memory too, and never releasing them may never release that memory... hence all the talk about memory leaks, or delays in memory clean up.

I have seen real world examples of this causing problems. For instance, I have seen ASP.Net web applications that eventually fail to connect to the database (albeit for short periods of time, or until the web server process is restarted) because the sql server 'connection pool is full'... i.e, so many connections have been created and not explicitly released in so short a period of time that no new connections can be created and many of the connections in the pool, although not active, are still referenced by undiposed and uncollected objects and so can't be reused. Correctly disposing the database connections where necessary ensures this problem doesn't happen (at least not unless you have very high concurrent access).

当一个对象实现IDisposable时,您应该调用Dispose(在某些情况下,Close将为您调用Dispose)。

您通常不必将对象设置为null,因为GC将知道一个对象将不再使用。

当我将对象设置为空时,有一个例外。当我(从数据库中)检索了很多需要处理的对象,并将它们存储在一个集合(或数组)中。当“工作”完成时,我将对象设置为null,因为GC不知道我已经完成了对它的工作。

例子:

using (var db = GetDatabase()) {
    // Retrieves array of keys
    var keys = db.GetRecords(mySelection); 

    for(int i = 0; i < keys.Length; i++) {
       var record = db.GetRecord(keys[i]);
       record.DoWork();
       keys[i] = null; // GC can dispose of key now
       // The record had gone out of scope automatically, 
       // and does not need any special treatment
    }
} // end using => db.Dispose is called

在c#中,你永远不需要将对象设置为空。编译器和运行时将负责找出它们何时不再在作用域中。

是的,你应该处理实现IDisposable的对象。

总是调用dispose。不值得冒这个险。大型托管企业应用程序应该受到尊重。不能做任何假设,否则它会反过来咬你一口。

别听她的。

很多对象实际上并没有实现IDisposable,所以你不必担心它们。如果他们真的超出了范围,他们将自动被释放。此外,我从来没有遇到过必须将某些内容设置为null的情况。

可能发生的一件事是,很多物体都可以保持打开状态。这将极大地增加应用程序的内存使用。有时很难判断这究竟是内存泄漏,还是您的应用程序只是在做很多事情。

内存配置文件工具可以帮助解决这类问题,但它可能很棘手。

此外,始终取消对不需要的事件的订阅。还要注意WPF绑定和控件。不常见的情况,但我遇到了这样的情况,我有一个WPF控件被绑定到一个底层对象。底层对象很大,占用了大量内存。WPF控件正在被一个新的实例所取代,而旧的实例由于某种原因仍然存在。这导致了一个大的内存泄漏。

在后台,代码写得很糟糕,但关键是你要确保没有使用的东西超出了范围。这需要很长时间才能用内存分析器找到,因为很难知道内存中的哪些东西是有效的,哪些不应该在那里。