【问题标题】:the relation between resource leaks and Memory leaks and performance资源泄漏和内存泄漏与性能的关系
【发布时间】:2012-08-09 19:03:25
【问题描述】:

对于资源泄漏,我指的是 Streams、StreamWriter(我想他们正在使用文件描述符)、句柄(GDI 或用户也使用图形字体)。很快,所有可关闭对象都可以算作资源! 如果应用程序中有一些资源泄漏。假设一些 InputStreams 没有关闭,它们是否也存在潜在的内存泄漏,因为垃圾收集器不会将它们从内存中删除?

另一个问题:资源泄漏会影响性能吗?

【问题讨论】:

    标签: c# java performance resources


    【解决方案1】:

    如果应用程序中存在一些资源泄漏。假设一些 InputStreams 没有关闭,它们是否也存在潜在的内存泄漏,因为垃圾收集器不会将它们从内存中删除?

    GC 会清理资源,无论它们是否关闭。如果不关闭,则唯一无法清理的资源是线程。

    当 Stream 在没有关闭的情况下被丢弃时,它会被集合上的终结器关闭。这有两个问题

    • 确切的时间或即使发生这种情况,也无法预料,这意味着文件可能不会被刷新,或者文件上保留了锁定以防止文件被删除。
    • 终结器是单线程,关闭资源可能需要一些时间。如果你有足够多的这些,终结器就跟不上,你会得到一个 OutOfMemoryError,因为你有大量的资源等待清理。

    用完资源后清理它们总是更好的。

    另一个问题:资源泄漏会影响性能吗?

    他们可以,这取决于泄露了多少。如果你没有太多的想法,你必须假设它是一个问题,除非你确信它不是。例如一个程序可能每天泄漏一个 24 字节的对象,或者它可能每秒泄漏 100 MB。并非所有的泄漏都是一样的。

    【讨论】:

      【解决方案2】:

      这取决于你所说的性能。我假设您说的是整体性能,这意味着内存消耗、速度等都很重要。

      这也取决于所使用的资源。一些资源(例如文件句柄)在进程退出时被恢复,因此泄漏只会在执行时成为问题。即使在您的应用程序执行之后,其他(如服务器或数据库连接)可能仍然存在泄漏。其他(如互斥锁等)应尽快释放。

      现在,后果取决于资源。如果资源是同一进程中的本机对象,那么泄漏它可能会泄漏相关的内存。如果资源是您锁定但未能解锁的互斥锁,那么您可能即将死锁您的应用程序。如果资源是一个连接,即使您停止使用它,服务器也会保持该连接打开。如果资源是一个文件,它可能会阻止其他应用程序(甚至您自己的应用程序)再次访问它。

      最后,虽然某些资源可能会泄露,但其他资源则不应该。就我而言,不应该泄露任何资源,除了 YMMV。

      因此,您应该养成始终正确释放您获得的资源(内存、文件、连接、互斥锁等)的习惯,无论该资源的感知重要性如何。这样做会训练您正确的编码模式(和思维方式)。

      RAIIException Safety 是您要搜索的关键字,如果您想探索这些概念。

      对于 C#,将需要 Dispose pattern(IDisposable 接口和终结器)和 using 关键字。另一种解决方案是使用 try/finallyfinally 类来释放资源,但这很难正确维护。

      在 Java 中,您需要 Java 7 (IIRC),并使用 AutoCloseable 接口和“try-with-resources”语句。与在 C# 中一样,您可以使用 try/finallyfinally 类来释放资源,但问题相同。

      【讨论】:

      • 如果资源泄漏(内存除外)也导致内存泄漏,您没有回答!我想答案是否定的,正如@Peter Lawrey 所写,GC 会将应用程序中专用的内存清理为文件句柄等资源!
      • @Govan : You didn't answer if resource leak (other than memory) is giving a memory leak too! :我确实回答了,但不是直接回答,因为问题取决于实现:If the resource is a native object in the same process, then leaking it will probably leak the associated memory. 例如,打开文件可能意味着分配了本机文件描述符结构在记忆中。那么,如果被管理的文件对象没有被释放,它的本机计数器部分,即结构体,将保留在内存中。 GC 将触及该内存,因为它是由本机代码分配的。
      【解决方案3】:

      Memory leak,顾名思义是一块没用的内存,但仍分配在您的进程空间中。考虑到 32 位机器上的 CLR 进程可能有大约 1.2GB 的内存,我会说在您的应用程序中出现内存泄漏是非常危险的

      当然,一切取决于您的应用程序有多大、关键任务以及其他因素。但是,无论如何,总是尽量避免它们,特别是如果你已经知道它们存在,特别是如果你已经知道它们在哪里。

      编辑

      资源泄漏实际上是同一个故事。资源分配内存,因此根据定义,它的泄漏会造成内存泄漏。

      希望这会有所帮助。

      【讨论】:

      • 我的问题是关于资源泄漏的!还有windows句柄、文件描述符、图形、字体等等
      • 我的问题是它们是否相同!但是,如果您阅读其他答案,有人认为资源泄漏并不总是造成内存泄漏!如果您将 InputStream 作为类中的成员变量并且您没有将其关闭,则 GC 将在清理类的实例时将其删除,但在操作系统上为其打开的文件描述符可能存在,直到应用程序进程死亡!据我了解其他人的回答!
      【解决方案4】:

      是的,内存泄漏意味着应用程序需要更频繁地运行垃圾收集器,并且每次运行时能够恢复的内存更少。当内存耗尽时,应用程序将崩溃。

      文件未关闭将导致应用程序在达到最大打开文件数时无法执行与文件或套接字相关的任何操作,这通常会使应用程序无法使用。

      【讨论】:

        【解决方案5】:

        当您保留对未使用对象的根引用时,可能会发生泄漏。 GC 无法收集它,因为它仍然可以访问。请特别注意附加到静态事件的静态实例和事件处理程序。

        当您将一次性对象保留为未处理时,在大多数情况下,它会延迟释放非托管资源并可能导致错误(流未刷新,...)。释放内存时,垃圾收集器对包含非托管资源的对象调用Finalizer。这比直接调用 Dispose 会减少 GC 的工作更昂贵。这是不可预测的,终结器可能最近才被调用。因此,如果您不调用 Dispose,它可能会导致临时资源匮乏(没有剩余的文件句柄,...)。

        因此,在此 Stream 上不调用 Dispose 不会导致内存泄漏,但您不应依赖 Finalization,因为它代价高昂且不可预测。此外,Dispose 不仅可以释放资源,还可以正确清除托管对象(刷新缓冲流,...)。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2015-12-22
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2014-02-10
          • 1970-01-01
          相关资源
          最近更新 更多