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

时间:2012-08-09 08:44:15

标签: c# java performance resources

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

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

5 个答案:

答案 0 :(得分:2)

  

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

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

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

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

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

  

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

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

答案 1 :(得分:1)

根据定义,

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

当然,一切取决于你的应用程序的大小,关键任务和其他因素。但是,无论如何,总是试图避免它们,特别是如果你已经知道它们存在,特别是如果你已经知道它们在哪里。

编辑

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

希望这有帮助。

答案 2 :(得分:1)

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

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

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

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

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

如果您想要探索这些概念,

RAIIException Safety是您要搜索的关键字。

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

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

答案 3 :(得分:0)

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

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

答案 4 :(得分:0)

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

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

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