1

我记得我是通过将图像从网络直接流式传输到位图中来加载图像的。关闭流,返回位图并将其保存在图像控件中。

当我执行 = loadPicture() 时,我例外,第一个位图会像 C++ 中的智能指针一样被释放。但它没有,我消耗了很多内存,直到我打电话给处置。所以我的问题是。

GC 和 Dispose 对象如何在 C# 中工作?为什么它不像 smart_ptr 那样实现?

4

4 回答 4

8

引用不是智能指针。让引用变量超出范围,将其替换为另一个值,和/或将其设置为 null 都无济于事

这只是 CLI /GC 设计的一部分......

Gargage Collection (GC) 将在需要时运行,并且应该清理使用的托管内存,以​​及(如果提供了终结器)任何非托管资源。但是对于确定性清理:这就是IDisposable. Dispose()当您完成这些对象时,您的工作就是处理它们 - 要么通过using,要么将其交给承担此责任的其他东西(常见的,例如,流/阅读器等)。

using (StreamReader reader = new StreamReader(myfile)))
{
   ...
}
于 2009-04-23T08:55:00.997 回答
2

当运行时认为有必要时,GC 就会启动。

基本规则是:当您使用 Disposable 类型(IDispose)时,您(作为程序员)应该尽快释放该类型使用的资源,在不再需要使用该类型时调用 Dispose。例如,当您读取文件时,您会在完成读取后立即关闭该文件。(在这种情况下调用 close 也会调用 dispose)。

于 2009-04-23T08:53:25.743 回答
1

您必须在任何实现 IDisposable 的对象上显式调用 Dispose,否则您的非托管资源将不会被释放。如果你不想显式调用它,那么你必须重写 Finalize 方法来调用 Dispose 方法——这就是为什么你会经常看到这个:

 class MyClass : IDisposable
 {
    ...

    ~MyClass()
    { 
       this.Dispose(false);
    }

    public void Dispose()
    {
       this.Dispose(true);
       GC.SuppressFinalize(this);
    }

    protected virtual void Dispose(bool disposing)
    {
        if (disposing)
        { /* dispose managed stuff also */ }

        /* but dispose unmanaged stuff always */
    }
 }
于 2009-04-23T09:25:53.873 回答
0

smart_ptr 被引用计数。虽然这允许在它们不再被任何代码引用时确定性地释放它们的资源,但它们确实有自己的问题:分配引用总是需要更新计数器,循环引用无法自动释放导致内存泄漏,内存管理器被更频繁地调用。

.NET 中的 GC 是一个全面的收集器。它从感觉应该释放内存的任何时间开始(通常由某些内存使用条件触发,但不是确定性的),并从构建系统中所有活动引用的列表开始(包括 CPU 寄存器中的引用、嵌套引用等) .)。这是有效的,因为我们处于无法进行指针运算等的托管环境中 - 系统可以跟踪所有引用。在构建了实时引用列表之后,它基本上会释放所有不知道不再使用的内存。当然,这只是一个基本的草图,对于非托管资源的效率和管理,还有更多的东西,比如对象生成、终结器等,但这对于基本理解它的工作原理并不重要。

IDisposable 接口用于实现一次性模式,这有助于您处理应以确定方式处置的对象。该模式是当不再需要对象时显式调用 Dispose() ,因此释放非托管资源或关闭句柄等,但不释放其内存。这将在稍后由 GC 完成,但稍后发生这并不重要,因为已经执行了资源的确定性释放。

于 2009-04-23T09:02:20.247 回答