记一次由于短命大对象致使fullGC的问题

写在前面

java内存申请和释放均是由jvm在控制。而释放每每会出现各类各样的问题,常常一个引用没处理好就引发内存泄漏,最后引起OOM。若是发生在重要业务系统还可能出现严重的生产事故。 所以内存使用必定要谨慎,特别是引用要及时断链。虽然jvm有GC(垃圾回收引擎),但只能清理没有引用的对象,所以对象在不使用时及时置null。固然,笔者对此是很当心的,但万万没想到仍是遇到了fullGC(old GC)。java

定义

jvm的GC

一般遇到的是堆区内存问题,也就是堆GC。jvm的GC发展到如今也经历不少发展了,如今主要仍是分代回收的思路。算法

eden space

伊甸园,新生对象放置的地方。数据库

survivor space

在jvm中的被回收过对象仍存活的地方。数据结构

old Generation

幸存区被清理后仍活着的对象就步入老年了。 大多数GC问题都在老年代中被发现,笔者遇到的问题也是在这里。eclipse

eden 和survivor都属于新生代,与old gen有明显差异,也就是这样决定了java程序不用主动回收也能在较好的状态运行。 eden和survivor空间相对old generation小不少,这也意味着存放的内存也少不少。jvm通常将长期引用(jvm会将对象分析其引用计数)的对象(屡次GC仍存活的)放在Old generation中。jvm

jvm堆区不一样区域使用的是不一样算法,eden和survivor的GC属于miniGC,也就是局部GC,特色是速度快,低延迟(1.标记复制算法与空间小的优点,2.GC时须要将全部线程挂起Stop The World)。而old generation发生GC则为FullGC,且old generation用的是标记整理算法,线程扶起时间会很长。频繁的fullGC多是程序设计不合理或内存参数不合理。工具

言归正传

这两天笔者遇到一个问题致使了fullGC发生。将进程进行dump分析 jmap命令配合工具 MAT(eclipse提供)发现是部分局部变量占用太多空间未及时释放形成而且占用了55%以上的内存空间。 为何局部变量还会未及时释放?查阅源代码发现全部引用处均未发现被全局对象、静态对象引用。ArrayList和LinkedList占用内存太高,但也未被全局对象和静态对象引用。spa

感受程序被幽灵附身了!!! 不存在的,直觉告诉我这种问题确定在本身的程序上。继续分析果真发现了问题所在:发现对象内的值关联性很是强,继续分析最终找到数据库查询参数。会不会是数据形成?面对这个疑问diff了最近数据的状况。线程

jvisual

芦山真面目

最近数据量暴增! 数量增长了6倍+,空间增长了3倍+。设计

因为数据结构和业务逻辑的特殊性将同条件的数据所有查出来处理了,因为数据全是相互存在引用,eden空间没法分配进行了miniGC。miniGC后空间仍然不足,就这样新生对象直接进入old generation。才生出来就进入老年 >_<。 而后因为处理很快结束,生成的这些对象也再也不有引用。可是在old generation中不会当即GC,并且只有fullGC才能将其释放。也就成了“短命的大对象”、“短命的老年对象” ==!

解决方案

知道了缘由就当即分析获得了解决方案。尽可能不要构建局部的大对象!!!所以将DB中查询出的量控制住,增长中间对象的数量,用完即置null。使得eden中及时GC,old generation增加稳定。 修改程序代码再将压一下,发现old generation增加缓下来了,问题解决。

若是遇到相似问题还能够用jconsole和jvisual两款工具实时监控jvm状态、对象实例指标等。 jconsole

很差的消息:jdk9已将jvisual去除,要使用jvisual请使用jdk8。jdk10中jconsole也没了。。 jmap分析吧。。。

相关文章
相关标签/搜索