【问题标题】:IDisposable : Memory leaksIDisposable:内存泄漏
【发布时间】:2011-12-23 18:40:54
【问题描述】:

我目前正在审查一个 C# 应用程序,我在其中看到:

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

在这个answer中,Henk表示不使用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)有什么风险?

【问题讨论】:

  • 错误示例。此方法不拥有个服务。它不应该 Dispose() 他们。第二个版本只处理了一些
  • @HenkHolterman:我编辑了第二个版本,包括你的评论。我可以根据什么知道是否应该致电Dispose()
  • 只有当 GetServices() 方法清楚地记录了责任转移给调用者时。您的版本很可能会导致运行时错误。
  • 拥有 ServiceControllers 的对象应该是对它们发起 Dispose 的对象。如果 GetServices() 正在创建 ServiceControllers 的新实例,那么您应该在此方法中启动 Dispose。否则,应该由“拥有”这些 ServiceController 的对象调用 Dispose 方法。
  • 查看ILDASM在System.ServiceProcess.dll上的输出,看来有必要对GetServices()返回的ServiceControllers进行Dispose()。在 GetServices 中,它们调用 ServiceController 的构造函数,将本机资源传递给它。值得注意的是,MSDN 示例代码没有调用 Dispose(); msdn.microsoft.com/en-us/library/…,这似乎是微软的一个错误,我希望他们能澄清或更新他们的文档。

标签: c# memory-leaks idisposable


【解决方案1】:

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

但是,如果未调用Dispose,则未正确写入的对象很可能会产生内存泄漏。我见过很多这样的物体的例子。

一般来说,如果您使用的是您拥有的IDisposable 实例,您应该始终调用Dispose。即使对象被正确写入,非托管资源也可以尽早清理而不是稍后清理,这对您有利。

编辑

正如 James 在 cmets 中指出的那样,在一种情况下,不调用 Dispose 可能会导致内存泄漏。一些对象使用Dispose 回调来解除长期事件的挂钩,如果它们保持连接状态,将导致对象驻留在内存中并构成泄漏。总是打电话给Dispose的另一个原因

【讨论】:

  • Dispose 中的事件处理程序未挂钩的情况如何?
【解决方案2】:

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

也就是说,在这种情况下添加“使用”无论如何都不会解决它,就好像您确实需要在每个实例上调用 dispose(在这种情况下通过“使用”隐式),它不会因为它在任何时候返回找到具有匹配名称的 ServiceController。

因此,如果您的第一次迭代找到了匹配的 ServiceController,那么所有其他 ServiceController 无论如何都不会被丢弃。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-10-08
    • 2013-01-20
    • 2011-10-31
    相关资源
    最近更新 更多