Memory Leak in Java

2025年5月2日 | 阅读3分钟

Java 提供开箱即用的内存管理。当我们使用 new 关键字创建对象时,JVM 会自动为该对象分配内存。如果应用程序不再使用该对象,垃圾回收器会自动删除该对象并为其他应用程序腾出空间。因此,程序员无需像其他过程式编程语言(C 和 C++)那样手动管理内存。尽管如此,Java 应用程序中仍有可能发生内存泄漏。在本节中,我们将了解Java 中的内存泄漏是什么、其原因、检测和修复内存泄漏

Java 中的内存泄漏是什么?

Java 中,内存泄漏是指垃圾回收器未能识别未使用的对象,并且它们无限期地保留在内存中,从而减少了分配给应用程序的内存量。因为未使用的对象仍然被引用,这可能导致 OutOfMemoryError。它还会影响应用程序的可靠性。下图代表了内存泄漏。

Memory Leak in Java

注意:我们可以为应用程序指定初始和最大堆大小。有两种参数(选项)用于设置堆大小:

  • -Xms<size>m
  • -Xmx<size>m

其中 m 表示 MB 为单位的大小。

内存泄漏的症状

如果任何 Java 应用程序出现内存泄漏,您会注意到以下情况:

  • 应用程序的性能持续下降。
  • 应用程序生命周期内的内存使用量增加。

内存泄漏的原因

Java 中的内存泄漏有以下原因:

  • 使用不需要的对象引用:这些是已不再需要的对象引用。垃圾回收器未能回收内存,因为另一个对象仍然引用该不需要的对象。
  • 使用长生命周期的静态对象:使用静态对象也会导致内存泄漏。因为它们在应用程序的整个生命周期内都保留在内存中。
  • 未能清理本地系统资源:由 Java 外部的函数(用 C 和 C++ 编写)分配的本地系统资源。JNI API 用于将本地库嵌入 Java 代码中。
  • 第三方库中的错误: AWT 和 Java Swing 包中的错误是内存泄漏的另一个原因。

防止内存泄漏

编写代码时,请记住以下几点,可以防止 Java 中的内存泄漏:

  • 不要创建不必要的对象。
  • 避免字符串连接。
  • 使用 StringBuilder。
  • 不要在会话中存储大量数据。
  • 在不再使用时使会话超时。
  • 不要使用 System.gc() 方法。
  • 避免使用静态对象。因为它们默认会保留整个应用程序的生命周期。因此,最好显式将引用设置为 null。
  • 始终在 finally 块中关闭 ResultSet、Statements 和 Connection 对象。

创建内存泄漏

让我们创建一个简单的 Java 程序来创建内存泄漏。

MemoryLeakExample.java

输出

Memory Leak in Java

在上面的程序中,我们创建了两个 Vector 对象并将大数字传递给它们。当我们运行上面的程序时,它会显示 java.lang.OutOfMemoryError。因为它没有在内存中占用空间。如果程序打印语句 本程序没有内存泄漏,则表示程序成功运行。

检测内存泄漏

检测内存泄漏是一项困难的任务。为了简化此任务,有许多工具可用于执行静态分析并检测内存泄漏:

  • JProbe
  • AppPerfect
  • Visual VM
  • Jprofiler
  • YourKit
  • GCeasy
  • JRockit

修复内存泄漏

解决内存泄漏问题的方案如下:

  • 使用 JVM 工具:有许多工具可用于优化代码并显示内存状态。
  • 使用堆转储(Heap Dump):这是一种用于解决内存泄漏问题的技术。它是给定时间点驻留在内存中的所有对象的快照。它还可以优化 Java 应用程序中的内存使用。它以二进制格式存储在 hprof 文件中。
  • 使用 Eclipse 内存泄漏警告:如果您使用 Eclipse 框架开发 Java 应用程序,Eclipse 会在遇到任何内存泄漏原因时定期显示警告和错误。