本文将提供完整的根本原因分析详细信息以及解决影响Oracle Weblogic Server 10.0生产环境的Java堆内存泄漏(Apache OpenJPA泄漏)的方法。 这篇文章还将演示在管理javax.persistence.EntityManagerFactory生命周期时遵循Java Persistence API最佳实践的重要性。

环境规格

  • Java EE服务器 :Oracle Weblogic Portal 10.0
  • 操作系统 :Solaris 10
  • JDK :Oracle / Sun HotSpot JVM 1.5 32位@ 2 GB容量
  • Java Persistence API :Apache OpenJPA 1.0.x(JPA 1.0规范)
  • RDBMS :Oracle 10g
  • 平台类型 :Web门户

故障排除工具

  • Quest Foglight for Java( Java堆监视)
  • MAT(Java 堆转储分析 )

问题描述与观察

生产中断后,最初由Weblogic生产支持团队报告了此问题。 最初的根本原因分析练习确实揭示了以下事实和观察结果:

  • 约2周的流量后,定期观察到生产中断。
  • 失败是由于Java堆(OldGen)耗尽所致,例如OutOfMemoryError:在Weblogic日志中发现Java堆空间错误。
  • 在一段时间后从Foglight监视工具检查了Java堆OldGen的空间利用率以及Java冗长的GC历史数据后,确认了Java堆内存泄漏。

发现上述问题后,决定移至RCA的下一个阶段,并对受影响的Weblogic(JVM)实例执行JVM 堆转储分析 。

JVM堆转储分析

**现在可以在此处获得解释以下JVM堆转储分析的视频。 为了产生一个
JVM堆转储受支持的团队确实使用了HotSpot 1.5 jmap实用程序,该实用程序生成了大约1.5 GB的堆转储文件(heap.bin)。 然后使用Eclipse Memory Analyzer Tool分析了堆转储文件。 现在,让我们回顾一下堆转储分析,以便我们了解OldGen内存泄漏的根源。

MAT提供了一个初始的泄漏可疑报告,这对于突出您的高内存贡献者非常有用。 对于我们的问题案例,MAT能够识别出泄漏嫌疑人,造成了将近600 MB的泄漏或占OldGen空间总容量的40%。

至此,我们找到了一个java.util.LinkedList实例,该实例使用了将近600 MB的内存,并已加载到我们的应用程序父类加载器之一(@ 0x7e12b708)。 下一步是了解泄漏的对象以及保留的来源。 MAT允许您检查应用程序的任何类加载器实例,为您提供检查加载的类和实例的功能。 只需提供地址(例如0x7e12b708)来搜索所需的对象,然后通过选择带有外向引用的“列表对象”>检查加载的类和实例。

从上面的快照中您可以看到,该分析非常有启发性。 我们发现内存保留源中有一个org.apache.openjpa.enhance.PCRegistry实例; 罪魁祸首是实现为LinkedList的_listeners字段。 供您参考,Apache OpenJPA PCRegistry在内部用于跟踪已注册的具有持久性的类。 在Apache OpenJPA 1.0.4版中暴露_listeners字段的PCRegistry源代码的片段下面。

/*** Tracks registered persistence-capable classes.** @since 0.4.0* @author Abe White*/
public class PCRegistry {// DO NOT ADD ADDITIONAL DEPENDENCIES TO THIS CLASSprivate static final Localizer _loc = Localizer.forPackage(PCRegistry.class);// map of pc classes to meta structs; weak so the VM can GC classesprivate static final Map _metas = new ConcurrentReferenceHashMap(ReferenceMap.WEAK, ReferenceMap.HARD);// register class listenersprivate static final Collection _listeners = new LinkedList();

现在的问题是,为什么这种内部数据结构的内存占用空间如此之大,并且随着时间的推移可能会泄漏? 下一步是深入研究_listeners LinkedLink实例,以便检查泄漏的对象。

最后,我们发现泄漏的对象实际上是我们的应用程序用来对Oracle数据库执行各种查询的JDBC和SQL映射定义(元数据)。 对JPA规范,OpenJPA文档和源代码的回顾确实确认了根本原因与javax.persistence.EntityManagerFactory的错误使用有关,例如缺少关闭新创建的EntityManagerFactory实例。

如果仔细查看上面的代码快照,您将意识到close()方法确实负责清理最近使用的元数据存储库实例。 这也确实引起了另一个问题,为什么我们要一遍又一遍地创建这样的Factory实例……调查的下一步是对我们的应用程序代码执行代码遍历,尤其是围绕JPA EntityManagerFactory和EntityManager对象的生命周期管理。

根本原因和解决方案

该应用程序代码的代码演练确实表明该应用程序在每个单个请求上都创建了EntityManagerFactory的新实例,并且没有正确关闭它。

public class Application {@Resourceprivate UserTransaction utx = null;// Initialized on each application request and not closed!@PersistenceUnit(unitName = "UnitName")private EntityManagerFactory emf = Persistence.createEntityManagerFactory("PersistenceUnit"); public EntityManager getEntityManager() {return this.emf.createEntityManager();}public void businessMethod() {// Create a new EntityManager instance via from the newly created EntityManagerFactory instance// Do something...// Close the EntityManager instance}
}

JPA EntityManagerFactory的此代码缺陷和改进程序的使用引起了OpenJPA _listeners数据结构内元数据存储库实例的泄漏或积累,这是从早期JVM堆转储分析中展示的。 该问题的解决方案是通过Singleton模式集中管理线程安全javax.persistence.EntityManagerFactory的管理和生命周期。 最终解决方案的实现如下:

  • 每个应用程序类加载器仅创建和维护一个javax.persistence.EntityManagerFactory静态实例,并通过Singleton Pattern实现。
  • 为每个应用程序请求创建并处置EntityManager的新实例。

请阅读Stackoverflow上的 讨论 ,因为我们实现的解决方案非常相似。 在将解决方案实施到我们的生产环境之后,不再观察到Java堆OldGen内存泄漏。

参考: OpenJPA:我们的JCG合作伙伴 Pierre-Hugues Charbonneau在Java EE支持模式和Java教程博客上的内存泄漏案例研究 。

翻译自: https://www.javacodegeeks.com/2013/03/openjpa-memory-leak-case-study.html

OpenJPA:内存泄漏案例研究相关推荐

  1. openjpa_OpenJPA:内存泄漏案例研究

    openjpa 本文将提供完整的根本原因分析详细信息以及解决影响Oracle Weblogic Server 10.0生产环境的Java堆内存泄漏(Apache OpenJPA泄漏)的方法. 这篇文章 ...

  2. java内存泄漏案例_寻找内存泄漏:一个案例研究

    java内存泄漏案例 一周前,我被要求修复一个有内存泄漏问题的webapp. 考虑到过去两年左右的时间里我已经看到并修复了数百个泄漏,我想这有多难. 但是事实证明这是一个挑战. 12小时后,我发现该应 ...

  3. Java Review - 线程池中使用ThreadLocal不当导致的内存泄漏案例源码分析

    文章目录 概述 Why 内存泄露 ? 在线程池中使用ThreadLocal导致的内存泄漏 概述 ThreadLocal的基本使用我们就不赘述了,可以参考 每日一博 - ThreadLocal VS I ...

  4. android内存泄漏原因分析,Android 内存泄漏案例分析总结(Handler)

    在Android开发开发中,操作不当很容易引起内存泄漏,这里主要记录下平时遇到问题,包括:静态变量(也包含集合).非静态的内部类.Handler.监听器,尤其是 Handler 在开发中要格外的注意. ...

  5. C语言内存泄漏案例及解决办法

    解决方案一:

  6. Android内存泄漏的检测流程、捕捉以及分析

    https://blog.csdn.net/qq_20280683/article/details/77964208 Android内存泄漏的检测流程.捕捉以及分析 简述: 一个APP的性能,重度关乎 ...

  7. Android 内存泄漏问题多多,怎么优化?

    作者 | 无名之辈FTER 来源 | CSDN博客 责编 | 夕颜 出品 | CSDN(ID:CSDNnews) 众所周知,Java因其拥有独特的虚拟机(JVM)设计,使其成为一门跨平台.内存自动管理 ...

  8. js中的内存溢出和内存泄漏

    内存溢出 内存溢出是一种程序运行会出现的错误,当程序所需要的内存大于剩余内存(机器能提供给你的内存),就会抛出内存溢出的错误 var obj = {} for (var i = 0; i < 1 ...

  9. Profiler分析内存抖动,Memory Analyzer(mat)分析内存泄漏(不懂砍我)

    前言: 最近在系统性的温习了一遍android性能优化.写博客是学习也是记录,希望在记录的同时也能帮助其他同学.最近我觉得我想出一个不懂系列."不懂揍我","不懂砍我&q ...

最新文章

  1. java dagger2_java – Dagger2不生成Daggercomponent类
  2. 搭建无人值守安装服务器(CentOS)
  3. 今天下午接到阔总编的电话
  4. CentOS 7时间命令timedatectl
  5. 查看linux服务器的系统信息
  6. 以前是传xml的吗_明明不太合适但是还是被用在配置文件和数据传输上的XML
  7. BugkuCTF-MISC题怀疑人生
  8. python3.5学习笔记:linux6.4 安装python3 pip setuptools
  9. map函数python返回值,Python中map函数使用
  10. 小白也能看懂的 Java 异常处理
  11. 关于计算机的幻想作文600字,科学幻想作文600字
  12. (转)区块链创造了ICO,但是无法守护ICO
  13. messagedigest 图片加密_MessageDigest对密码进行加密
  14. CentOS7安装Pentaho Server 8.1 CE 社区版
  15. 常见分布的数学期望和方差
  16. 在繁杂的网页中揪出email地址
  17. linux安装软路由,软路由安装设置教程【详细步骤】-太平洋IT百科手机版
  18. html调用短信接口发送消息的实例,HTTP电脑发送短信接口调用示例
  19. api 接口响应数据格式有哪些
  20. 美通企业周刊 | 生成式AI成为全球焦点;诺维信和科汉森股东批准合并;沈阳威斯汀酒店开业...

热门文章

  1. java 字符数组与字符串_用于字符串和数组的5种简单有效的Java技术
  2. gradle junit5_JUnit 5和Selenium –使用Gradle,JUnit 5和Jupiter Selenium设置项目
  3. akka的介绍_Akka笔记–演员介绍
  4. JMetro版本11.6和8.6发布
  5. singleton设计模式_Java Singleton设计模式
  6. java 编译 器 ide_在没有IDE的情况下编译和运行Java
  7. Sparklens:Spark应用程序优化工具
  8. 基于drools_Drools:基于PHREAK堆栈的评估和向后链接
  9. JDK 11:新的默认收集方法toArray(IntFunction)
  10. 无需再忙了:Lambda-S3缩略图,由SLAppForge Sigma钉牢!