内存溢出异常

除了程序计数器之外,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连接越来越多,虚拟机崩溃

解决:将异步调用改为生产者/消费者的消息队列实现