内存溢出异常
除了程序计数器之外,jvm的其他几个运行时区域都存在着OOM异常的可能性
java堆溢出
对象数量达到最大堆的容量限制后
虚拟机栈和本地方法栈溢出
线程请求的栈深度大于虚拟机所允许的最大深度
虚拟机在扩展栈时无法申请到足够的内存空间
方法区和运行时常量池溢出
生成大量的class的情况
JDK的可视化工具
JConsole:java监视与管理控制台
概述;类;vm摘要;MBean;
内存(相当于jstat);
线程(相当于jstack);
VisualVM:多合一故障处理工具
显示虚拟机进程以及进程的配置,环境信息(jps,jinfo)
监视应用程序的CPU,GC,堆,方法区以及线程的信息(jstat,jstack)
dump以及分析堆转储快照(jmap,jhat)
方法级的程序运行性能分析,找出被调用最多,运行时间最长的方法
离线程序快照
调优案例分析
1.高性能硬件上的程序部署策略
问题:将网站堆内存固定在12GB,网站不定期出现长时间失去响应的情况。
原因:失去响应是因为过大的堆内存,程序设计产生成批大对象,进入老年代,GC停顿导致的。
解决:给java虚拟机分配超大堆的前提是,把握程序的Full GC频率控制得足够低。
控制GC频率的关键是不能有成批的,长时间生存的大对象产生,这样才能保证老年代的稳定。
现阶段64位jdk性能测试结果普遍低于32位jdk,多数人选择使用若干个32位虚拟机建立逻辑集群:在一台物理机器上启动多个应用服务器进程,每个进程分配不同端口,在前端搭一个负载均衡器。
无session复制的亲和式集群:均衡器按照一定的算法(一般根据sessionId分配)将一个固定的用户请求永远分配到固定的一个集群节点处理。
2.集群间同步导致的内存溢出
问题:亲和式集群,节点间没有session同步,需要有一些数据共享,使用JBossCache构建一个全局缓存。不定期出现多次内存溢出问题
原因:JBossCache 的缺陷。JBossCache在发送数据时有一个全局filter,把数据操作时间同步到所有的节点中,当网络情况不满足,重发数据在内存中不断堆积
解决:需要被集群共享的数据,使用类似JBossCache的缓存框架同步时,可以读操作频繁,不能写频繁。
3.堆外内存导致的溢出错误
问题:GC并不频繁,Eden区,surviver区,老年代以及永久代均表示压力不大,但还是报错内存溢出
原因:除了java堆和永久代,还有些区域会占用一定的内存:Direct Memory;线程堆栈;socket缓冲区...
4.服务器jvm进程崩溃
问题:使用了异步方式调用另一个系统的web服务,速度不对等,导致等待的socket连接越来越多,虚拟机崩溃
解决:将异步调用改为生产者/消费者的消息队列实现