当前位置: 首页>>技术教程>>正文


Java内存泄漏简介


什么是Java中的内存泄漏

通常,当应用程序不再使用对象时,应该对这些对象进行垃圾回收。但是,如果仍然引用这些对象,则垃圾回收器无法从工作内存中删除这些对象。此外,在应用程序的整个生命周期中,还有一些对象保留在内存中(例如:静态变量)。因此,此类应用程序消耗越来越多的内存,并导致OOM(Out Of Memory)问题。

内存泄漏与生产系统

wso2中,我几乎没有分析某些生产系统中的内存泄漏的经验。生产系统中发生内存泄漏的可能性很高,因为这些系统运行较长时间而没有重启。在这种情况下,即使内存泄漏很小,它也会累积泄漏,最后可能会导致严重的内存泄漏。这样的内存泄漏很难在本地重新创建,但是我们可以尝试通过使系统长时间保持负载运行来尝试复现问题。

内存泄漏的原因

内存泄漏的主要原因是不良的编程。

  1. 大量使用静态变量
    在静态类中,可以使用类成员而不启动类。因此,在使用static时,在创建类实例之前,将在JVM中创建其类的对象。因此,此类静态变量将在程序执行期间保留在内存中,不符合垃圾回收的条件。
  2. 未关闭的流/连接
    这将导致底层资源泄漏和内存泄漏。底层资源泄漏一般是由操作系统级资源的泄漏。 JVM使用内存来跟踪这些基础资源,从而导致内存泄漏。
    未关闭流和连接的主要原因是:因为开发人员忘记了关闭打开的流/连接。在Java 7之后,我们有了try-with-resources,不用手动关闭流。
  3. 具有缺少 hashCode()或 equals()实现的对象的Hashset。如果我们不重写 hashCode()和 equals()方法并尝试将重复条目添加到集合中,则将无法识别重复项,而是将多个重复项添加到集合中。而且,一旦添加副本,就无法删除这些重复副本。

什么是堆转储(heap dump)

堆转储是某个特定时间点Java进程内存的快照。触发快照时,堆转储包含Java对象和类。

为什么我们需要分析堆转储

堆转储分析有助于找到对象的创建位置,并在源中找到对这些对象的引用。该调查的最终目标是找到消耗过多内存的对象以及正在运行的应用程序中这些对象的存放位置。

如何分析堆转储

1.在基线和高流量中捕获堆转储。这意味着当系统运行正常且流量很高时,我们需要进行两个堆转储。
命令:

jmap-dump:format=b,file=<file-path><pid>

其中pid:是Java进程ID,我们要捕获其堆转储。 file-path:是堆转储将写入数据的文件路径。

2.在系统崩溃之前捕获堆转储
由于很难确定系统崩溃的地点,因此我们可以使用以下命令在这种情况下获取堆转储。建议您始终在所有应用程序中都配置此属性,因为我们不知道何时发生OOM错误。

XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=<file-path>

file-path:是堆转储将写入的文件路径。
java -XX:+ HeapDumpOnOutOfMemoryError

3.确定在步骤1和步骤2之间大小在增长的对象。

几个内存分析工具

  • MAT
  • Java Flight Recorder
  • Eclipse内存分析器
  • IBM HeapAnalyzer

JAVA内存泄漏

参考资料

本文由《纯净天空》出品。文章地址: https://vimsky.com/article/4542.html,未经允许,请勿转载。