将对象设置为null是否确定性地处理对象?

时间:2013-12-06 09:57:45

标签: c#

我有点奇怪的问题,即使有相同问题的线程,我也找不到明确的答案。

问题:如果我将对象设置为null,是否会导致dispose方法(已实现)被确定地调用?例如,在下面的代码中,通过将pricingEnvironment对象设置为null,Dispose会立即调用吗?我知道如果没有调用Dispose,终结器将在某个时刻启动pricingConnvironment对象。

代码:

public interface IPricingService
    {
        double GetPrice(string instrument);
    }

    public interface IPricingEnvironment:IDisposable
    {
        void Initialize();
    }

    public class PricingEnvironment : IPricingEnvironment
    {
        public void Dispose()
        {
            DisposeObject();
        }

        public void Initialize()
        {
            //initialize something leaky
        }

        private void DisposeObject()
        {
            //release some leaky unmanaged resource
        }

        ~PricingEnvironment()
        {
            DisposeObject();
        }
    }

    public class PricingService:IPricingService, IDisposable
    {
        private IPricingEnvironment pricingEnvironment;
        public PricingService()
        {
            pricingEnvironment = new PricingEnvironment();
        }
        public double GetPrice(string instrument)
        {
            pricingEnvironment.Initialize();
            return 1d;
        }

        public void Dispose()
        {
            //Will this dispose the leaky resource used by pricing environment deterministically?
            pricingEnvironment = null;
        }
    }

谢谢, -Mike

6 个答案:

答案 0 :(得分:3)

在.NET中无法保证调用终结器。垃圾收集器可能根本不会调用它(例如,因为根本不需要垃圾收集器永远释放内存),并且在一个终结器抛出异常的情况下,其他终结器将不会执行(参见MSDN)。如果你在对象上调用SuppressFinalizer,你甚至可以抑制终结器。

话虽如此,当然也无法保证立即调用终结器(可能会稍后调用或根本不调用)。

您应该明确调用Dispose或使用using - 语句,以便妥善处理您的对象。作为安全网,您仍然可以从终结器中呼叫Dispose。事实上,这也是MSDN中的示例所展示的最佳做法。

关于这个主题的好读物是Raymond Chen的帖子:

  

<强> Everybody thinks about garbage collection the wrong way

答案 1 :(得分:1)

不,它不会。

这样做:

    public void Dispose()
    {
        // check if object has IDisposble implemented
        IDisposable disposePricing = pricingEnvironment as IDisposable;
        if (disposePricing!=null)
        {
            disposePricing.Dispose();
        }
    }

并阅读this CLR Inside Out article from 2007

答案 2 :(得分:0)

没有*方法可以确定垃圾收集器何时收集您的对象并调用其终结器(并且遵循代码中的逻辑,Dispose方法)。 以下是垃圾收集不可预测的一个很好的例子:http://ericlippert.com/2013/06/10/construction-destruction/

即使GC开始并收集第一代对象,PricingEnvironment的实例也将在第一个集合中存活,并被置于最终化队列中。

您应该通过明确调用Dispose或使用using块来确定性地处置您的对象。

*您实际上可以使用GC.Collect()强制它,但您不应该这样做。

答案 3 :(得分:0)

虽然计算机按定义是确定性的,但是当释放分配的内存时,完全取决于语言实现的垃圾收集器。将其设置为null将导致将引用计数减少到已分配的内存,但是在达到范围结束时会发生这种情况。

答案 4 :(得分:0)

我猜你在处理被垃圾收集时会感到困惑。

Dispose释放非托管资源(数据库连接或文件句柄)

GC释放占用的内存不再使用的对象

处置是确定性的,因为它在您调用Dispose时运行(无论是在using块中显式还是隐式)

垃圾收集本质上是非确定性的。它运行时适合。只有这样可以释放内存引用。 例如,如果GC运行的生成级别与对象当前所在的级别不同,则不会收集它。

您可以通过调用GC.Collect()显式运行GC,但问问自己是否应该再次猜测GC。

答案 5 :(得分:0)

^是的;虽然值为null,但垃圾收集器不知道您是否分配了新内容。当你到达范围的末尾时会调用它。