本文概述
在平常场景进行发邮箱,短信以及APP 的推送消息一些特别活动。java
这种业务的特色是短期以内会有大量的用户进入APP进行参与,这时候系统的压力会忽然增长。面试
在业务流量高峰的时候,CPU的使用率十分十分高,而且直接致使系统卡死,没法进行任何请求的处理,在系统重启以后会好一段时间,可是后面又会立刻卡死。算法
经过这种思路排查,结果果真发现FULL GC的频率十分高,竟然一分钟一次FULL GC,频率实在是过高了。数组
继续排查发现使用jstat发现并不存在内存不合理的状况,而且对象也是正常进入老年代,同时永久代的内存竟然也是正常的。缓存
这时候又会考虑一个问题,一分钟一次FULL GC,证实老年代空间是不够的,虽然新生代进入老年代是正常的,可是若是老年代 自己对象就很是多,会不会也会出现问题呢?按照这个思路继续排查,果真发现老年代GC以后 竟然还有那么多对象存活。并发
真相大白,缘由就是老年代被大量对象占满了,很容易触发FULL GC,咱们可使用Jmap的工具排查这里面的内容,固然,也可使用mat(memory anaylyze tool)进行排查,可是本文不涉及工具的使用介绍,大体介绍一下mat的处理流程:jvm
MAT的排查进程: jmap -dump:format=b,file=文件名[服务进程ID] 1. 首先内存快照,能够看到当前内存状况 2. 其次发现内存泄露 3. 建立的对象占比量过大 4. 发现缘由是jvm缓存没有及时进行清理,致使内存愈来愈大 5. 排查结果是本地内存没有进行限制,同时没有按期淘汰算法 6. 解决办法使用一些EHCACASH的缓存便可
其实按照排查思路进行一步步排查,要找到问题其实并非很难。ide
String.split是如何形成内存泄露的 业务就直接跳过,这里重点关注问题分析和解决流程。工具
不用说,标题已经暴露了一切,可是到底是如何分析出来的?这里也不兜圈子,直接给一张图,:测试
从这里看到java.lang.Thread
的主线程main 线程,局部变量竟然占用了**24.97%**的内存的对象。这里告诉你问题出如今java.lang.Object[]
数组,这个数组占用大量的内存。
在1的下面有一行蓝色的 Details,进入以后能够看到下面的内容:
在
Problem Supspect 3
里面也能够看到这里面占用了大量的String
对象。
从这里能够看到在main线程里面,有一个arrayList集合占用了几乎全部的内存,这个List显然也是Object[]的数组,而且在内容里面存在Demo1$Data的对象实例。
从这个分析咱们知道了如何分析出内存占用的问题,其实大胆猜想加上实用工具测试能够基本均可以验证出问题。
知道了占用是由于Object[]数组的问题,接着来看下链路追踪的状况:
如上图所示,咱们点击statictrace进入到具体的代码界面:
答案在最下面的图:
咱们能够明显的看到是String的问题,经过代码搜索发现有一个String.split
多是产生问题的缘由。
这里就涉及一个JDK源代码的问题了:
在JDK6的版本,一个字符串的底层是基于下面的形式进行存储的,好比"yes yes yes yes"使用空格切分是以下的形式:
["yes","yes","yes","yes"]
可是到了Jdk7,他给每一个切分出来的字符串都建立了一个新的数组,意思就是说每次切分都切分出一个新的数组,这里可能无法理解,因此咱们给出代码:
if (xxxxx)// 一大堆判断,不用管,总之大部分状况你都会进这个If判断 { return list.subList(0, resultSize).toArray(result); } return Pattern.compile(regex).split(this, limit);
这个sublist
毫无疑问就是罪魁祸首了,致使JDK版本升级了以后内存占用爆高也是这个代码,这个代码干了啥呢?
public List<E> subList(int fromIndex, int toIndex) { subListRangeCheck(fromIndex, toIndex, size); return new SubList(this, 0, fromIndex, toIndex); }
这个也是典型的面试题,可用看到返回了当前List的视图,同时这个视图会随着数组的改变而改变,关于这个对象细节百度一大堆,这里不讨论,这里须要关注的是这个new
。
到这里相信读者也清楚为何split()
方法会致使大量的Object[]
数组被构建出来,SubList
底层依然是一个数组!
说白了仍是代码的质量问题,不用想能够知道须要从代码层面修复问题,解决fot循环里面的split()
方法。
因此字符串的操做尤为须要谨慎,由于字符串天生的不可变的特性,使用频率很是高的同时也很容易出现问题。
总结: 这篇文章内容很少,主要为下面两个点: