笔记:深入理解JVM 第5章 调优案例分析与实战

1、每天15万 PV 的在线文档类型网站

环境:4 CPU,16GB 内存, 64位 CentOS 5.4

问题:网站失去响应

原先JVM配置:JDK1.5,  -Xmx12G  -Xms12G

解决过程:发现问题来自GC停顿(12G内存 的 Full GC 需要12秒),内存中暂存文件导致“朝生夕灭”大量大对象,采用默认吞吐量优先收集器。

最终JVM配置:使用5个32位JDK作为逻辑集群,每个进程2GB内存,Apache服务作为前端负载均衡,垃圾回收改为CMS回收


2、集群间同步导致的内存溢出

环境:两台服务器,每台2个CPU、8GB内存、启动3个WebLogic,构成6个节点的亲和式集群,JBossCache作为全局缓存

问题:内存溢出。

解决过程:配置-XX:+HeapDumpOnOutOfMemoryError ,检查heap文件,发现是JBossCache问题,缓存多次被写,。

最后结论:缓存可以频繁读,但是不能频繁写。


3、堆外内存导致的溢出

环境:1CPU,4GB内存,32位Window系统,小型B/S的电子考试系统,使用了CometD技术

问题:不定时抛出内存溢出异常

原先配置:

解决过程:加入-XX:HeapDumpOnOutOfMemoryError 无果,使用jstat 无果,查日志发现是Direct Memory 溢出:OutOfMemory:null, at  sun.misc.Unsafe.allocateMemory (Native Method)。

CometD技术 用到了NIO 技术。Direct Memory  不能像老生代、新生代那样,发现空间不足了就通知收集器进行垃圾回收,他只能等待老生代Full GC的时候,顺便帮他清理内存的废弃对象,否则只能等待抛出异常。

最后结论:除了Heap 和 Perm ,这些区域也会占用内存: Direct Memory(-MaxDirectMemorySize)、线程栈 (-Xss)、Socket 缓存、JNI代码、虚拟机本身和GC


4、外部命令导致系统缓慢

环境:4CPU,Solaris,Glassfish

问题:请求响应慢,CPU使用率高

解决过程:通过Rumtime.getRuntime().exec() 执行外部shell脚本, 启动大量新进程,消耗大量时间。JVM执行Rumtime.getRuntime().exec() 流程:先复制一个与当前JVM拥有一样环境变量的进程,再使用这个新的进程去执行外部命令,最后退出,这种调用方式即使命令很快能执行完成,频繁创建进程的开销也非常可观。

解决方法:不使用shell 脚本,使用Java API。


5、服务器JVM进程崩溃

环境:2台服务器,2个CPU,8GB内存,WebLogic

问题:JVM自动关闭

解决过程:看日志,"Java.net.SocketException:Connection reset" 。因为远端连接到另外一个系统,调用另一个系统 完成Task,另一个系统处理速度非常慢,于是本系统积累了越来越多的等待线程和Socket连接。

解决方法:将调用另外一个系统的方式改成生产者-消费者模式的消息队列。 


6、不恰当数据结构导致内存占用过大

环境:后台RPC服务器,64位虚拟机

原先JVM配置:-Xms4g -Xmx8g -Xmn1g -XX:+UseParNewGC -XX:+UseConcMarkSweepGC 

问题:加载80M的数据文件时候,每次Minor GC 造成停顿500 毫秒。

解决过程:看日志,新生代有多次Minor GC还存在的大对象

解决方法:去掉Survivor,-XX:+SurviorRatio=65536  ; 加入参数 -XX: MaxTenuringThreshold=0  -XX:+AlwaysTenure,将Minor GC后的对象立即进入老生代。修改程序。


7、Windows 虚拟内存导致长时间停顿

环境:带心跳检查的GUI桌面程序,每15秒一次心跳

问题:心跳检测有误,偶尔1分钟停顿

原先配置: -Xmx256M

解决过程:加入 -XX:PrintGCApplicaitonStoppedTime -XX:+PrintGCDateStamps -Xlooger:gclogs. 看日志 .程序在最小化时候,其工作内存被自动交换到磁盘的页面文件中

加入:-Dsun.awt.keepWorkingSetOnMinimize=true





 

posted @ 2014-12-21 21:47  lihui1625  阅读(141)  评论(0编辑  收藏  举报