@
目录一、操作文档类功能,大量大对象直接进入老年代
问题现象
- 操作文档类功能,大量大对象直接进入老年代,没有在Minor GC时被清理,导致老年代迅速消耗殆尽频繁进行Full GC,在服务器内存较大的情况下,Full GC会造成长时间停顿。
解决方法
通过单一Java虚拟机管理大量的内存
- 控制Full GC 频率,完善代码逻辑,尽量使对象都满足朝生夕灭的原则,维持老年代的稳定;
- 使用增量回收模式的垃圾收集器,例如G1;
- 由于指针膨胀和数据类型对齐补白导致相同程序,在64位虚拟机中消耗的内存大于32位虚拟机中消耗的内存,可以开启压缩指针功能。
同一台服务器上部署若干Java虚拟机
使用逻辑集群来使用硬件资源,同一个程序在同一台服务器上使用不同端口号启动多个进程,然后搭建一个负载均衡服务器,以反向代理的方式来分配访问请求(不考虑高可用性需求,使用无Session复制的亲和式集群,均衡器固定将一个用户请求固定分配到一个固定的集群节点);
可能产生的问题:
- 磁盘资源竞争导致I/O异常;
- 很难高效利用资源;
- 大量使用本地缓存的应用会造成较大的内存浪费(把本地缓存改为集中式缓存);
二、异步请求大量累积
异步请求大量累积,当请求异常时,接口超时导致双方服务速度不对等,最终累积了大量未完成的web请求超出了虚拟机承受能力,导致崩溃。
解决:
- 修复超时接口
- 异步web请求改为消息队列。
三、排查问题
老实说,JVM调优是一个非常庞大问题集;着手点因为实际问题的差异也各不相同;
排查问题:
- jmap jstat 等指令查看堆使用情况,渐次定位问题;
- jvisualvm 查看Java堆各个区域回收情况,查看JVM启动参数是否合理;
- 生成 GC 日志查看GC类型,统计各种类型的GC次数,记录GC耗时,关注异常GC;(可以使用GC日志分析工具,也可以自己用文本文档分析);
- 生成堆快照并分析,查看堆内是否有某些对象数量是否异常;
可能出现的问题以及原因
- Full GC频繁:老年代空间较小,收集速度滞后于新生代
设置老年代:新生代比例 3:1 (通常3:1为较好的选择),G1 收集器不建议使用会破坏G1的停顿预测模型。
-XX:NewRatio=3
拓展堆内存大小,最大最小设置相同,避免运行过程中堆内存浮动
-Xms4192m
-Xmx4192m
- Full GC 时间过长,这是本文讨论的第一个问题
-
使用增量垃圾回收:G1 / (CMS + ParaNew)
//G1 不区分新生代老年代 -XX:+UseG1GC // 或者,CMS(老年代) + ParaNew(新生代) -XX:+UseParNewGC -XX:+UseConcMarkSweepGC
-
问题太多,JVM优化也只是往更优的方案靠近,没有万能的优化,只有针对具体问题的具体优化,如果后续碰到问题我会持续更新到这里。