2011-11-07 92 views
3

目前,我正在做一个C#应用程序的审查中,我看到的是:IDisposable接口:内存泄漏

public static bool ServiceExists(string servicename) 
{ 
    ServiceController[] services = ServiceController.GetServices(); 
    foreach (ServiceController s in services) 
    { 
     if (s.ServiceName == servicename) 
     { 
      return true; 
     } 
    } 
    return false; 
} 

在这种answer,亨克说,不使用Dispose()(或using)不会产生内存泄漏,是真是假?

能否保持现有的代码有它,或者我应该写成才,如:

public static bool ServiceExists(string servicename) 
{ 
    ServiceController[] services = ServiceController.GetServices(); 
    bool exists = false; 

    foreach (ServiceController s in services) 
    { 
     using(s) 
     { 
      if (s.ServiceName == servicename) 
      { 
       exists = true; 
      } 
     } 
    } 

    return exists; 
} 

什么是在这种情况下使用Dispose()(或using)没有风险?

+0

错误的例子。此方法不会提供服务。它不应该Dispose()它们。而第二个版本仅部署其中的一部分。 –

+0

@HenkHolterman:我编辑了第二个版本,包括你的评论。我可以根据什么来确定是否应该调用'Dispose()'? –

+0

只有当GetServices()方法清楚地表明责任转移给调用者时。您的版本可能会导致运行时错误。 –

回答

6

正确编写的对象不应该导致内存泄漏,如果它是Dispose方法未被调用。现在,控制非托管资源的.Net对象应该通过SafeHandle实例来实现。即使没有调用Dispose,这些将确保本机内存被释放。

但是,如果没有调用Dispose,那么对于写入不正确的对象很可能产生内存泄漏。我见过很多这样的对象的例子。

一般而言,如果您使用的是您拥有的IDisposable实例,则应始终致电Dispose。即使对象被正确写入,您的好处是非托管资源可以在早期而不是在以后清理。

编辑

正如詹姆斯指出了意见存在这样的情况不是要求Dispose可能导致内存泄漏一个案例。一些对象使用Dispose回调来解除长时间存在的事件,如果这些事件一直存在,会导致对象驻留在内存中并构成泄漏。还有一个原因总是要拨打Dispose

+1

在Dispose中取消挂钩的事件处理程序的情况如何? –

+1

@JamesL我会更新我的答案,谈论这个。 – JaredPar

2

这一切都取决于什么ServiceController.GetServices()正在做什么。如果在调用ServiceController时创建了新的ServiceController实例,则可能会导致内存泄漏,具体取决于其Dispose方法中需要执行的操作(ServiceController)。

这就是说,在这种情况下添加'使用'无论如何不会修复它,就好像你需要在每个实例上调用dispose(在这种情况下隐式地通过'using'),它不会每当它返回时它找到一个名称匹配的ServiceController。

因此,如果您的第一次迭代找到匹配的ServiceController,则所有其他ServiceController都不会被处置。

+0

你是对的,我编辑了第二个例子 –