【译】Java中的内存泄漏是什么?转载
在 Java 中创建应用程序时,开发人员可以使用new关键字在其软件中创建托管对象。程序员不需要在他们的代码中显式删除这些托管对象,因为垃圾收集器负责删除不再需要的对象。只要对象由垃圾收集器处理,就可以了。但是,如果垃圾收集器无法删除不再引用的对象,那么您的应用程序中就有可能发生内存泄漏。
Java 中的内存泄漏是指应用程序不再需要的对象在Java 虚拟机 (JVM)中仍然存在的状态。当应用程序意外挂起不再需要的对象引用时,就会发生内存泄漏。由于应用程序增加(和意外)内存使用,内存泄漏会随着时间的推移导致性能下降。
本 Java 编程教程讨论了 Java 中的内存泄漏、它们发生的原因以及开发人员如何防止它们。
顺便说一句,程序员可以使用应用程序性能监控 (AMP) 工具和软件来检测内存泄漏并帮助追踪导致资源消耗的问题。我们有一篇很棒的文章,介绍了面向开发人员的顶级应用程序性能监控工具。
什么是内存泄漏?
内存泄漏是不再需要的对象在 JVM 内存中保持活动状态的情况。Java中内存泄漏的原因有多种,这些原因也导致Java应用程序中产生不同类型的内存泄漏。随着时间的推移,内存泄漏会导致应用程序性能下降,因为您的应用程序会增加(和意外)对内存和资源的使用。
应该注意的是,垃圾收集器擅长定期收集未被引用的对象。但是,它不会收集那些仍在使用的对象,即仍然有引用的对象。这正是发生内存泄漏的地方。为了帮助防止内存泄漏,重要的是设计程序以在不再需要内存时释放内存。
此外,程序员应该意识到内存泄漏的可能性,并确保为他们彻底测试他们的程序。当发生内存泄漏时,程序会慢慢消耗越来越多的内存,直到最终崩溃。
什么是堆栈和堆中的内存泄漏?
在 Java 中,您可能会遇到堆栈和堆内存的内存泄漏。当一个对象被创建但从未从堆中删除时,就会发生堆内存泄漏。如果代码正在引用不再需要但从未删除该引用的对象,则可能会发生这种情况。最终,堆将被未使用的对象填满,应用程序很快就会耗尽内存。
当方法不断被调用但从未退出时,就会发生堆栈内存泄漏。如果存在无限循环,或者每次使用不同的数据调用方法但从未使用过数据,则可能会发生这种情况。最终,堆栈将被填满,程序将耗尽内存。
为什么Java中会发生内存泄漏?
Java 中内存泄漏的最常见原因之一是应用程序未能正确释放它不再需要的资源。当应用程序为对象分配内存但从不释放它们时,即使不再需要它们,也会发生这种情况。发生这种情况时,为这些对象分配的内存永远不会被释放,并且应用程序的整体内存使用量会随着时间逐渐增加。
这可能是由于编程错误,或者仅仅是因为程序员忘记包含会这样做的代码。在任何一种情况下,它都可能导致受影响程序的性能下降,并且在最坏的情况下,可能会导致程序崩溃。
内存泄漏可能由于编程错误而发生,即当您获取内存但在不再需要相同内存时不释放它们。要解决此问题,您应该编写必要的代码来释放获取的内存。
如何防止 Java 中的内存泄漏
在 Java 中防止内存泄漏的最佳方法之一是使用JProfiler之类的工具,它可以帮助您识别代码分配内存但未正确释放内存的位置。JProfiler 还可以帮助您识别内存泄漏的其他潜在原因,例如保留对不再需要的对象的引用。
一旦确定了内存泄漏的潜在来源,您就可以修改代码以确保在不再需要资源时正确释放它们。这有助于减少应用程序的整体内存占用并提高其整体性能。
静态字段、实例字段和线程本地内存泄漏
程序员在 Java 应用程序中可能会遇到几种类型的内存泄漏。由静态字段引起的泄漏是最常见的。当您在不再需要的类中使用静态字段时,会发生这种情况。
当类的实例字段引用不再需要的对象时,就会发生“实例字段”泄漏。当线程局部变量引用一个对象而不是在多个线程之间共享实例时,就会发生“线程局部”泄漏,直到线程处于活动状态。
如何避免 Java 中的内存泄漏:最佳实践
您可以遵循以下最佳实践来避免 Java 中的内存泄漏:
- 使用最新版本的 Java。
- 使用 Eclipse MAT、Visual VM、JProbe、YourKit、JRockit、AppPerfect 等内存泄漏检测工具。
- 使用分析器工具来检测内存泄漏。
- 避免在代码中使用System.gc()方法调用
- 使用内存泄漏检测工具,例如 YourKit、JProfiler 等
- 避免使用内部类。
内存泄漏可能难以诊断和修复。但是,通过了解原因,您可以检测并修复它们。您应该能够按照以下步骤找到任何内存泄漏的根本原因:
- 确定存在内存泄漏(即,使用分析器或性能监视器)
- 检查调用堆栈是否有未释放的引用
- 确定这些对象没有被垃圾回收的原因
- 编写代码以手动删除此类对象
关于 Java 内存泄漏的思考
当程序未能释放未使用的资源(例如对象、数据库连接或文件句柄)时会发生内存泄漏,而当一个对象保留对另一个对象的引用时会发生引用泄漏,即使后者不再需要。这些非预期的对象引用会阻止内置的 Java 垃圾收集进程清除这些对象获取的内存。在本文中,我们研究了内存泄漏是什么、为什么会发生以及如何防止 Java 中的内存泄漏。
作者:Joydip Kanjilal