我有点奇怪的问题,即使有相同问题的线程,我也找不到明确的答案。
问题:如果我将对象设置为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
答案 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();
}
}
答案 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,但垃圾收集器不知道您是否分配了新内容。当你到达范围的末尾时会调用它。