以下案例全部引用---深入理解java虚拟机 周志明 著 的案例:
一.案例分析
1.1高性能硬件上的程序部署策略
例如,一个15万PV(page view)/天左右的在线文档类型网站最近更换了硬件系统,新的硬件为4个CPU、16GB物理内存,操作系统为64位CentOS 5.4,Resin作为Web服务器。整个服务器暂时没有部署别的应用,所有硬件资源都可以提供给这个访问量不算太大的网站使用。管理员为了尽量利用硬件资源选用了64位的jdk1.8,并通过-Xmx和-Xms参数将java堆固定在12GB。使用一段时间后发现使用效果并不理想,网站经常出现不定期长时间失去响应的情况。
分析原因:通过服务器监控运行状态发现:主要原因还是因为GC停顿所导致的,虚拟机运行的时候,回收12GB的堆,一次Full GC的停顿时间高达14秒,并且由于程序设计的关系,访问文档时要把文档从磁盘提取到内存中,导致内存中出现很多文档序列化的大对象,这些大对象很多都进入了老年代,没有在新生代 GG 中清理掉。这种情况下即使有12GB的堆,内存也很快被消耗殆尽,由此导致每隔十几分钟出现十几秒的停顿。
解决办法:
1)修改产生大量变量的代码
2)使用jdk来管理内存
对于用户交互性强、对停顿时间敏感的系统,可以给java虚拟机分配超大堆的前提是有把握把应用程序的Full GC频率控制的足够低,至少不能影响用户使用,譬如十几个小时乃至一天才出现一次Full GC ,这样可以通过在深夜执行定时任务的方式触发Full GC 甚至自动重启应用服务器来保存内存可用空间在一个稳定的水平;
3)使用若干个64位虚拟机建立逻辑集群来利用硬件资源
书里面原文是:主要是现阶段64位JDK的性能测试结果普遍低于32位JDK
但是我个人在使用64位jdk的时候感觉性能并没有出现什么问题,而且32位的虚拟机对于很多软件以及插件不是很兼容,性价比不高,不利于重构,而且各大bat公司基本上都是使用64位虚拟机建立集群。所以我这里更新一下。
建立5个64位jdk的逻辑集群,每个进程按2G内存计算(其中堆占1.5GB),占用了10GB内存。另外建立一个Apache服务作为前端均衡代理访问门户。考虑到用户对相应速度比较关心,因此改为CMS收集器进行垃圾回收。
总结:三个解决办法可以同时使用,顺序为1,3,2。至于为什么,自己考虑。
2.2集群间同步导致的内存溢出
例如:有一个基于B/S的MIS系统,硬件为两台2个CPU、8GB内存的HP小模型,服务器是WebLogic9.2,每台机器启动了3个WebLogic实例,构成一个6个节点的亲合式集群。由于是亲合式集群,节点之间没有进行Session同步,但是有一些需求要实现部分数据在各个节点间共享。开始这些数据存放在数据库中,但由于读写频率竞争很激烈,性能影响较大,后面使用JBossCache构建了一个全局缓存。全局缓存启动后,服务正常使用了一段较长的时间,但最近却不定期地出现了多次的内存溢出问题。
JBossCachhe版本本身缺陷,JBossCachhe官方已经讨论过很多关于类似的问题了;
关于书上还有的几个案例,我个人感觉可读性不大,我和就不在讲述。
总结:对于GC和Full GC的控制一般只能是通过对堆内存的控制来调节GC的时间;