Hibernate 一级缓存导致某保险公司核心系统Weblogic中间件内存溢出的故障诊断


title: Hibernate 一级缓存导致某保险公司核心系统Weblogic中间件内存溢出的故障诊断
author: rocklei123
date: 2018-09-02 22:15:45
tags: [Hibernate, 缓存,内存溢出,WebLogic]
categories: Hibernate

1.客户环境

  • Weblogic版本:9.2
  • Linux :suse 12
  • JDK版本: Sun JDK 1.5

2.故障现象

在 201X 年 X 月 X 日早上 10 点多时,某保险公司核心系统多个
Weblogic 的应用服务器都极度缓慢,正常的业务都无法开展。

3.详细分析

应用缓慢原因

检查 Weblogic 的相关日志文件,发现有内存溢出的情况发生,如下:
java.lang.OutOfMemoryError: Java heap space

并产生了相关的内存溢出 HeapDump 文件:java_pid25528.hprof 随后对该文件进行下一步分析,可知:

在这里插入图片描述

其中占据内存较多的两组对象都是产生了 Stuck 的 Weblogic 线程,分别占用的内存是 84.85%和 10.40%,这两部分加起来是 95.25%,

说明已经占用了整个 Weblogic Server 的绝大部分内存。

进一步分析内存溢出对象

进一步分析,发现大量的对象都被缓存在
(org.hibernate.engine.StatefulPersistenceContext)中.
Hibernate 一级缓存导致某保险公司核心系统Weblogic中间件内存溢出的故障诊断_第1张图片

在这个缓存中的 对象是我们的业务对象

在这里插入图片描述

业务对象如下:

com.**.scms.inf.model.ScmsCcommission
com.**.scms.inf.model.ScmsCcomissionId

由于这些缓存的数据无法释放,系统在业务量较大时,内存迅速 在 2 分钟内从 1G 增长到 4G,并且不断地进行 Full GC,导致系统极其缓慢。

StatefulPersistenceContext 解密

SessionImpl

Hibernate的一级缓存就是指Session缓存。通过查看Session接口的实现类——SessionImpl.java的源码可发现有如下两个类:

161   	private transient ActionQueue actionQueue;
162   	private transient StatefulPersistenceContext persistenceContext;

actionQueue它是一个行动队列,它主要记录crud操作的相关信息。
persistenceContext它是持久化上下文,它其实才是真正的缓存。

persistenceContext缓存存储方式

当执行完以下这句代码:

Customer customer = session.get(Customer.class, 1);

就会向一级缓存中存储数据,一级缓存其底层使用了一个Map集合来存储,Map的key存储的是一级缓存对象,而value存储的是快照。通过在这句代码上打个断点,然后以debug的方式运行,Watch一下session会看得更加清楚,如下:

Hibernate 一级缓存导致某保险公司核心系统Weblogic中间件内存溢出的故障诊断_第2张图片

Hibernate 一级缓存导致某保险公司核心系统Weblogic中间件内存溢出的故障诊断_第3张图片

Hibernate session的清理方法

从如下的代码中,也可以看出,session在执行相关清理工作时,也会执行persistenceContext.clear();

public void clear() {
  281   		errorIfClosed();
  282   		checkTransactionSynchStatus();
  283   		persistenceContext.clear();
  284   		actionQueue.clear();
  285   	}


  466   	/**
  467   	 * clear all the internal collections, just
  468   	 * to help the garbage collector, does not
  469   	 * clear anything that is needed during the
  470   	 * afterTransactionCompletion() phase
  471   	 */
  472   	private void cleanup() {
  473   		persistenceContext.clear();
  474   	}

StatefulPersistenceContext源码

[StatefulPersistenceContext源码](http://www.docjar.com/html/api/org/hibernate/engine/StatefulPersistenceContext.java.html "StatefulPersistenceContext源码)

org.hibernate.engine.StatefulPersistenceContext
结合以上代码和该类的实现类可以确定是一个缓存上下文引用,而且从session.cleanup()方法session.cleanup()实际调用的就是persistenceContext.clear(),注意这句话**clear all the internal collections, just to help the garbage collector;
**

/**
58   import org.hibernate.util.IdentityMap;
59   import org.hibernate.util.MarkerObject;

   62    * A PersistenceContext represents the state of persistent "stuff" which
   63    * Hibernate is tracking.  This includes persistent entities, collections,
   64    * as well as proxies generated.
   65    * 

66 * There is meant to be a one-to-one correspondence between a SessionImpl and 67 * a PersistentContext. The SessionImpl uses the PersistentContext to track 68 * the current state of its context. Event-listeners then use the 69 * PersistentContext to drive their processing. 70 * 71 * @author Steve Ebersole 72 */

4.建议

由于 Hibernate 的一级缓存是其内部使用的,无法关闭或停用(随着Session 销毁)。从
Hibernate 的手册或文档中可知,Hibernate 的一级缓存的清除可通过以下方式:
1)对于单个对象的清除:

Session session=sessionFactory.getCurrentSession(); session.evict(entity);

2)对于实体集合的清除:

Session session=sessionFactory.getCurrentSession(); session.clear();
建议在程序中加入对 Hibernate 一级缓存的清除工作,以便可以其
内存数据可以及时释放。

关于Hibernate缓存问题可参考:
Hibernate缓存策略

5.可能场景

如果应用会定时启动几个quartz任务来处理复杂且影响页面、响应时间的业务,这部分业务的业务数据是从数据库查的,只有业务数据全都被处理完后这个quartz才会结束。
当这几个 quartz任务的业务数据较多的时候,就会有很多对象被填入一级缓存这样一来持久化上下文中保存的对象越来越多。最终导致OOM.

6.参考

http://www.docjar.com/html/api/org/hibernate/engine/StatefulPersistenceContext.java.html

http://www.docjar.com/html/api/org/hibernate/impl/SessionImpl.java.html

https://blog.csdn.net/yerenyuan_pku/article/details/70148567

https://www.cnblogs.com/hyl8218/p/5076338.html

7.了解Hibernate缓存策略请看

Hibernate缓存策略

Hibernate缓存策略

8.欢迎关注米宝窝,持续更新中,谢谢!

米宝窝 https://rocklei123.github.io/

你可能感兴趣的:(Hibernate)