JVM调优案例分析与实战
2016-11-28 16:47
525 查看
一、内存溢出
1、堆内存溢出
模拟代码以及JVM设置:CMS的gc日志分为一下几个步骤,重点关注initial-mark和remark这两个阶段,因为这两个阶段会stop进程。
初始标记(init mark):收集根引用,这是一个stop-the-world阶段。
并发标记(concurrent mark):这个阶段可以和用户应用并发进行。遍历老年代的对象图,标记出活着的对象。
并发预清理(concurrent preclean):这同样是一个并发的阶段。主要的用途也是用来标记,用来标记那些在前面标记之后,
发生变化的引用。主要是为了缩短remark阶段的stop-the-world的时间。
重新标记(remark):这是一个stop-the-world的操作。暂停各个应用,统计那些在发生变化的标记。
并发清理(concurrent sweep):并发扫描整个老年代,回收一些在对象图中不可达对象所占用的空间。
并发重置(concurrent reset):重置某些数据结果,以备下一个回收周期
运行日志解读:
2、栈深度溢出
模拟代码及JVM参数设置:
3、运行时常量池内存溢出
模拟代码及JVM参数设置:从中可以看出,Perm区引发的Full Gc效果很不明显,并且打印出来的内存映射快照,不包括Perm区的内存。
4、运行时方法区溢出
模拟代码及JVM参数设置:
二、典型案例分析
案例分类 | 案例分析 | 案例现象 | 排查方法 | 解决方法 |
---|---|---|---|---|
JVM堆内存溢出。 | 1、CMS内存溢出案例。 现象:CMS一段时间不重启或者不发布,一般为两三天,晚上就会报警,报警内 容为Full GC,内存溢出。重启后问题马上就可以恢复。 分析:通过分析内存,发现下面这个类的interfaceMap占用了大部分内存,进而 发现是这个消息消费者线程Deal2Listener占用大部分内存。 结论:监听线程不同于用户请求线程,不会在用户请求结束后主动释放内存,而 会一直存在这个线程,除非重启或者重新部署。而这个监听线程不断往线程缓存 中存入数据,并且垃圾回收期无法进行回收,最终导致堆内存溢出。 2、合作取数据库数据量过大导致堆内存溢出。 | Full GC次数较多,并伴随着 java.lang.OutOfMemoryError: Java heap space下面的 报错信息 | 添加参数-XX: +HeapDumpOnOutOfMemoryError 找到对应的内存溢出内存快照, 用mat打开对应的内存快照, 来进行快照分析。 | 保存现场后 重启服务器。 分析内存快照 找到内存 溢出的原因, 修复代码。 |
Perm区内存溢出。 | 1、调用的jar包中有String.intern()的调用。 2、groovy脚本导致的FullGC问题。 | jmap -heap 12004查看内存分配情况。 堆中还有大量的内存未使用,但是不断 进行Full GC,并且每次GC效果不明显。 | 查看permSize大小,看大小是否设置的合适,检查是否有大量的常量设置,检查是否有cglib等反射生成的代码。 | 代码中或者jar包有显示的String.intern()的调用,修复代码。 |
直接分配内存溢出 | 1、产品中心对内存设置过大,导致频繁Full GC。 JVM堆空间分配的内存过大,导致对外内存不够用,系统 不定期抛出内存溢出异常。 | 所有的堆内存和Perm区都压力不大,只有抛出异常时才进行Full GC。 (如果设置了-XX:+DisableExplicitGC开关的话,对中还有很多空闲内存,却不断抛出内存溢出异常) 添加参数-XX: +HeapDumpOnOutOfMemoryError 无任何内存映像文件产生。 | 在异常栈中能够找到Unsafe.allocateMemory等字样。 | 检查系统内存和JVM内存,看JVM内存设置的是否合理。 检查-Xss看线程堆栈是否设置的合理。 检查代码中是否有Socket的使用和JNI代码。 |
JVM线程打满。 | 4、外部调用超时、数据库连接超时、数据库死锁导致JVM线程打满。 | 系统接口调用出现502、504错误, 并伴随着一定的连接超时报错。 | jstat -l 进程号,打印进程中的线程 栈信息,通过查看线程栈信息,找出进程中是否有Block或者Running的线程。 | 外部接口调用、数据库连接或者处理都有超时控制。 |
GC导致长时间停顿 | 5、JVM内存扩容后,不定期出现长时间失去响应的现象。 | 不定期出现长时间失去响应的现象 | 查看Full GC记录,发现Full GC的停顿时间过长 | 1、调整CMS收集器不设置为吞吐量 优先,或者设置最长停顿时间。 2、若干个虚拟机建立集群来充分利用硬件资源。 |
三、速度调优
1、类加载和编译时间优化:JDK版本的选择、禁止字节码校验。2、GC时间优化:JVM初始内存设置、GC收集器选择。
加上-Xint 禁止掉及时编译,总的启动时间从12s上升到了42s。
加上-Dfile.encoding=UTF-8 -Xmx1g -Xmn512m -XX:PermSize=128m -XX:MaxPermSize=128m 进行了3次Full GC。
加上 -Xms1g 后 ,没有进行Full GC。
加上-XX:+UseConcMarkSweepGC,选用虽然进行了16次Full GC,但是停顿时间比较短,看出CMS垃圾收集器的优越性。
参数调优基本都是基于实践,推荐的设置:JVM系列三:JVM参数设置、分析
-Xmx3000M -Xms3000M -Xmn600M -XX:PermSize=500M -XX:MaxPermSize=500M -Xss256K -XX:+DisableExplicitGC -XX:SurvivorRatio=4 -XX:+UseConcMarkSweepGC -XX:+UseParNewGC -XX:+UseCMSCompactAtFullCollection -XX:CMSFullGCsBeforeCompaction=0 -XX:+UseCMSInitiatingOccupancyOnly -XX:CMSInitiatingOccupancyFraction=70
-XX:+HeapDumpOnOutOfMemoryError
-XX:+PrintGCDetails -XX:+PrintGCTimeStamps
四、QA
1、Q:CMS是否和Full GC等价?A:1. Full GC == Major GC指的是对老年代/永久代的stop the world的GC
2. Full GC的次数 = 老年代GC时 stop the world的次数
3. Full GC的时间 = 老年代GC时 stop the world的总时间
4. CMS 不等于Full GC,我们可以看到CMS分为多个阶段,只有stop the world的阶段被计算到了Full GC的次数和时间
,而和业务线程并发的GC的次数和时间则不被认为是Full GC
5. Full GC本身不会先进行Minor GC,我们可以配置,让Full GC之前先进行一次Minor GC,因为老年代很多对象都会引用到新生代的对象,
先进行一次Minor GC可以提高老年代GC的速度。比如老年代使用CMS时,设置CMSScavengeBeforeRemark优化,让CMS remark之前先进行一次Minor GC。
2、Q:concurrent mode fail失败后,serial old会作为备选搜集器?
A:如果并发搜集器不能在年老代填满之前完成不可达(unreachable)对象的回收,或者年老代中有效的空闲内存空间不能满足某一个内存的分配请求,
此时应用会被暂停,并在此暂停期间开始垃圾回收,直到回收完成才会恢复应用程序。这种无法并发完成搜集的情况就成为并发模式失败(concurrent mode failure)。
在并发模式失败的情况下,serial old会作为备选搜集器,进行一次全局GC(Full GC),因此serial old也算是CMS的“替补”。
显然,由于serial old的介入,会造成较大的停顿时间。
参考:
http://www.open-open.com/lib/view/open1432109559864.html
http://blog.csdn.net/historyasamirror/article/details/6245157
http://ifeve.com/jvm-cms-log/
内存溢出异常实战
关于施用full gc频繁的分析及解决
JVM QA经典问答:http://blog.csdn.net/iter_zc/article/details/41802365
GC定义:http://www.tuicool.com/articles/jq2yIza
CMS GC MODE : http://blog.csdn.net/g7n3f/article/details/50828793
相关文章推荐
- Java之JVM调优案例分析与实战(4) - 外部命令导致系统缓慢
- JVM笔记——调优案例分析与实战
- Java之JVM调优案例分析与实战(5) - 服务器JVM进程奔溃
- 笔记:深入理解JVM 第5章 调优案例分析与实战
- Java之JVM调优案例分析与实战(2) - 集群间同步导致的内存溢出
- JVM调优案例分析与实战:高性能硬件上的程序部署策略
- 深入理解JVM笔记五-调优案例分析与实战
- 深入学习Java JVM - 调优案例分析与实战
- Java之JVM调优案例分析与实战(3) - 堆外内存导致的溢出错误
- 深入理解JVM笔记五-调优案例分析与实战
- Java之JVM调优案例分析与实战(1) - 高性能硬件上的程序部署策略
- JVM之调优案例分析与实战
- [深入理解Java虚拟机]第五章 调优案例分析与实战
- 《Spark商业案例与性能调优实战100课》第18课:商业案例之NBA篮球运动员大数据分析代码实战之核心基础数据项编写
- Spark商业案例与性能调优实战100课》第11课:商业案例之通过纯粹通过DataFrame分析大数据电影点评系仿QQ和微信、淘宝等用户群分析与实战
- Spark商业案例与性能调优实战100课》第20课:大数据性能调优的本质和Spark性能调优要点分析
- Spark商业案例与性能调优实战100课》第16课:商业案例之NBA篮球运动员大数据分析系统架构和实现思路
- Spark商业案例与性能调优实战100课》第3课:商业案例之通过RDD分析大数据电影点评系各种类型的最喜爱电影TopN及性能优化技巧
- 《Spark商业案例与性能调优实战100课》第13课:商业案例之纯粹通过DataSet进行电商交互式分析系统中特定时段段访问次数TopN
- 《Spark商业案例与性能调优实战100课》第6课:商业案例之通过Spark SQL实现大数据电影用户行为分析