资源泄漏与内存泄漏和性能之间的关系

资源泄漏我指的是Streams,StreamWriter(我认为他们正在使用文件描述符),Handles(GDI或用户也是Graphics字体)。 很快所有Closable对象都可以算作资源! 如果应用程序中存在一些资源泄漏。 假设一些InputStreams没有关闭,它们是否也可能因为垃圾收集器从内存中删除它们而导致内存泄漏?

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

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

它也取决于所使用的资源。 进程退出时会恢复某些资源(例如文件句柄),因此泄漏只会在执行时出现问题。 其他(如服务器或数据库连接)即使在您的应用程序执行后仍可能保持泄漏。 其他人(如互斥体等)应该尽快释放。

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

最后,虽然有些资源可能泄露,但其他资源不应该泄露。 就我而言,任何资源都不应该被泄露,但YMMV。

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

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

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

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

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

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

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

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

完成后,最好还是清理资源。

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

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

根据定义, Memory leak是一个无用的内存,但仍在您的专业领域中分配。 考虑到32位机器上的CLR进程有大约1.2GB的可能内存,我想说在你的应用程序中发生内存泄漏是非常危险的

当然, 一切都取决于有多大,关键任务+其他因素应用程序。 但是,在任何情况下, 总是尽量避免它们,特别是如果你已经知道它们存在,特别是如果你已经知道它们在哪里。

编辑

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

希望这可以帮助。

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

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

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

当你留下一个未加工的一次性物品时,在大多数情况下,它会推迟释放非托管资源,并可能导致bug(Stream没有冲洗,……)。 释放内存时,垃圾收集器会在包含非托管资源的对象上调用Finalizer 。 这比对Dispose的直接调用更昂贵,这将减少GC的工作。 这是不可预测的,终结者可能最近被称为终结者。 因此,如果您不调用Dispose,则可能导致临时资源不足(没有剩余的文件句柄,…)。

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