调优案例
一在高性能硬件上部署程序
1.通过64位JDK使用大内存
面临的问题:1,内存回收导致的长时间停顿2,现阶段64位JDK的性能测试结果普遍低于32位JDK3,需要保证程序足够稳定,因为这种应用要是产生堆溢出几乎无法产生堆转储快照,哪怕产生快照也几乎无法进行分析4,相同程序在64位JDK消耗 的内存一般比32位的JDK大,这是由于指针膨胀以及数据类型对齐补白等因素导致的
2.使用若干个32位虚拟机建立逻辑集群来利用硬件资源
面临的问题:1,尽量避免节点竞争全局的资源,各个节点如果同时访问某个磁盘文件的话(尤其是并发写操作容易出现问题),很容易导致IO异常2,很难最高效率的利用某些资源池,譬如连接池,一般都是在各个节点建立自己独立的连接池,这样就有可能导致一些节电池满了而另外一些节点仍有较多空余,尽管可以使用集中式JNDI,但这个有一定复杂性并且可能带来额外的性能开销3,各个节点仍然不可避免的收到32位内存限制影响,在32位windows平台中每个进程只能使用2GB的内存,考虑到堆以外的内存开销,堆一般最多只能开到1.5G,在某些Linux或UNIX系统中,可以提升到3GB乃至接近4GB的内存,但是32位中仍受到最高4GB的内存限制4,大量使用本地缓存(如大量使用HashMap作为K/V缓存)的应用,在逻辑集群中会造成较大的内存朗威,因为每个逻辑节点都有一份缓存,这时候可以考虑把本地缓存改为集中式缓存
二 集群间同步导致的内存溢出
当构成一个亲合式集群的时候,节点之前没有进行Session同步,有一些需求要实现部分数据在各个节点间共享,构建了一个JBossCache的全局缓存,JBossCache是基于自家的JGroups之间进行集群之间的数据通信。会不定期出现多次内存溢出的问题,
当集群共享的数据要使用类似JBossCache这种集群缓存来同步的话,可以允许读频繁操作,因为数据在本地内存有副本,读取的操作不会耗费多少资源,但是不应当有过于频繁的写操作,那样会带来很大的网络同步开销
MSI服务端有一个负责安全校验全局的Filter,每当接收到请求时,均会更新一次最后操作时间,并把这个时间同步到所有的节点上去。使得一个用户在一段时间内不能多次在多台机器上登录。
三 堆外内存导致的溢出错误
除了java堆和永久代之外,我们还应该注意到这些区域还回占据较多的内存
Direct Memory:可通过-XX:MaxDirectMemorySize调整大小,内存不足时抛出OutOfMemoryError或者OutOfMemoryError:Direct buffer memory
线程堆栈:可通过-Xss调整大小,内存不足时抛出StackOverFlowError(纵向无法分配,即无法分配新的栈针)或者OutOfMemoryError:unable to cteate new native thread(横向无法分配内存,无法建立新的线程)
socket缓存区:每个Socket链接都receive和send两个缓存区,分别占大于37K和25K内存,连接多的话这块内存占用也比较可观,如果无法分配,则会抛出IOException : Too many open files异常
JNI代码:如果代码中使用JNI调用本地库,那么本地库使用的内存也不再堆中
虚拟机和GC:虚拟机,GC的代码执行也要消耗一定的内存
四 外部命令导致系统缓慢
五 服务器JVM进程崩溃
六 不恰当数据结构导致内存占用过大
七 由windows虚拟内存导致的长时间停顿
eclipse的调优
1. 升级JDK1.6的性能变化及兼容问题
2.编译时间和类加载时间的优化
3.调整内存设置控制垃圾收集频率
运行期的新生代的空间太小,Eden区+Survivor区 很小,所以-Xmn调整新生代的大小
运行期主要是老年代容量在自动扩充,我们可以设置-Xms和-XX:PermSIze参数值和-Xms和-XX:MaxPermSize参数值一样,这样就强制虚拟机在启动的时候就把老年代和永久代的容量固定下来防止自动扩展
用jstat -gccause查询一下最近GC的原因发现,代码System.gc()显示触发GC,可以在eclipse.ini中加入-XX:+DisableExplicitGC屏蔽掉System.gc()
4.选择收集器降低延迟