美文网首页
遭遇 hibernate in clause 的内存泄漏

遭遇 hibernate in clause 的内存泄漏

作者: htger | 来源:发表于2018-12-20 12:15 被阅读7次

问题描述

最近遇到内存泄漏的问题:在阿里服务器上部署了一个定时爬虫,用 springboot 写的项目;使用 webmagic 爬虫框架,最终数据写入 mysql 并且添加 elasticsearch 索引;当跑到一个月的时候服务出现“假死”,表现是内存用光了,程序一直在 full gc , 抛出 OOM (overhead limit exceed)。

附上一天的 gcviewer 图:

图1-1 gc 最近日志 图1-2 gc 20小时前日志 图1-3 程序一直full gc

从上面的 gc 日志得出:老年代小幅度只增不减,存在内存泄漏。为了方便定位到问题,使用内存分析工具而不去检查源码。


实验准备

计划

我将一样的程序在测试环境运行,记录 gc 日志以及 dump 转储文件,通过工具定位内存泄漏。

工具

MAT 一款功能强大的 java 堆内存分析器,用于查找内存泄漏以及内存消耗情况。

概念1: 浅堆(shallow heap)和深堆(retained heap)

浅堆只与对象结构有关,如图4所示,在32位系统中 int 4 字节,对象引用4字节,对象头8字节;那么 String 对象一共是3*4 + 4 + 8 = 24字节,这就是他的浅堆大小,不管char[] 有多少个字符始终是24字节。

图2.2-1 String 结构

深堆是指对象A的保留集(通过对象A直接或者间接访问到的所有对象)中所有对象的浅堆大小之和,即对象A被释放的所有对象(包括自己)。

概念2:支配树(dominator tree)

图2.2-2 左边是引用关系,右边是支配树

在 MAT 中提高称为支配树的对象图,体现对象实例间的支配关系。 如果引用对象A必经过对象B,则认为对象B为对象A的直接支配者。

有如下性质:对象 A 的子树表示对象A的保留集;对象A支配对象B,则对象A的直接支配者也支配对象B;支配树的边与对象引用图的边不直接对应

如图5,对象A和B的直接引用是根对象,则A和B被根对象直接支配;对象C经过A引用,也可经过B引用,则由根对象支配; F和D相互引用,但是引用F需要经过D,而引用D不一定经过F,则D直接支配F

概念3:垃圾回收根(MAT javaBasic->GC Roots 可直接展示)

实际分析:

内存泄漏存在以下特点:老年代越来越大,某些类内存占比大,被垃圾回收根引用,存在大对象。

程序跑了3天,得到内存转储文件;查看 MAT 内存泄漏分析报告:

图3.1-1 内存泄漏报告

查看 QueryPlanCache 中缓存含有 in 的 sql 语句:

图3.1-2 in-sql语句

解决方案参见:https://stackoverflow.com/questions/31557076/spring-hibernate-query-plan-cache-memory-usage


参考资料

《Java 程序性能优化》 葛一鸣等编著,清华大学出版社

相关文章

网友评论

      本文标题:遭遇 hibernate in clause 的内存泄漏

      本文链接:https://www.haomeiwen.com/subject/lytcxftx.html