深入理解JVM(五)——JVM调优 Eclipse调优
来源:互联网 发布:phpcms 模板使用php 编辑:程序博客网 时间:2024/06/07 07:37
在开发,测试环境,我们可以通过JConsole或者VisualVM去监控Java程序的运行时,但是生产环境是不会给你安装这些应用的。JDK1.6之后,JMX管理默认都是开启的,所以你也可以通过JMX管理达到监控和调优的目的。这也是我下一阶段的工作一部分。
大体的需求包括:
- 显示虚拟机进程以及进程的配置,环境信息(jps,jinfo)
- 监视应用程序的CPU,GC,堆,方法区以及线程信息(jstat,jstack)
- dump以及分析堆转储快照(jmap,jhat)
- 方法级的程序运行分析,找出被调用最多的,运行时间最长的方法
- 离线程序快照:收集程序的运行时配置,线程dump,内存dump等信息建立一个快照,可以将离线发给开发者进行BUG反馈
下面介绍JVM优化案例
高性能硬件上的程序部署策略
背景:日PV量15万左右的在线文档类型网站,硬件升级前使用32位系统1.5GB的堆,用户刚到网站比较缓慢,不会停顿。
现状:最近更换硬件,新的硬件为4个CPU,16GB物理内存,操作系统64位的JDK1.5,Resin作为Web服务器。设置-Xmx和-Xms参数将Java堆固定在12GB。
问题:使用一段时间后并不理想,网站经常出现不定期长时间失去响应的情况。
原因:监控服务器运行情况发现网站失去响应是由GC停顿导致的,虚拟机运行在Server模式,默认吞吐量优先收集器,回收12GB的堆,一次Full GC的停顿时间高达14秒。由于程序设计是文档访问,很多大的对象都进入老年代,即使有12G的堆,也会被很快耗尽。
方案:选择多个32位虚拟机建立逻辑集群来利用硬件资源(部署多个应用服务进程,在前端搭建一个负载均衡器,以反向代理的方式来分配请求)
实施:建立了5个32位JDK的逻辑集群,每个进程按照2GB内存计算(堆固定在1.5GB),占用了10GB内存。建立Apache服务器作为前端均衡代理访问门户。考虑用户对响应速度关心,并且文档服务器压力集中在磁盘和内存访问,CPU资源敏感较低,改为CMS收集器。
使用64为管理大内存有以下问题:
- 内存回收导致的长时间停顿
- 现阶段,64位JDK的性能测试结果普遍低于32位JDK
- 需要保证程序足够稳定,因为这种应用堆溢出几乎无法产生的堆转储快照,因为太大了(十几GB甚至更大的Dump文件)
- 相同程序在64位消耗的内存比32位大,由于指针膨胀,以及数据类型对齐补白等
集群间同步导致的内存溢出
背景:基于B/S的MIS系统,硬件为两台2个CPU,8GB内存的HP小型机,服务器为WebLogic9.2,每台机器有3个实例。节点之间没有session同步,但有需求需要实现部分数据在节点之间共享。
现状:采用JBoosCache构建了一个全局缓存,全局缓存启动后,服务器正常使用了一段时间,但最近不定期出现内存溢出的问题。
问题:内存溢出
原因:加上参数-XX:+HeapDumpOnOutOfMemoryError运行一段时间,最近一次溢出,分析heapdump文件,发现jgroups异常。JBoosCache是通过jgroups进行集群间通讯的,使用协议栈的方式收发数据包,信息在传输失败需要重发,在收到确认消息之前,所有的消息必须在内存中保留。而MIS中有一个全局的Filter,每次收到请求会更新最后操作时间,并且同步到每个节点,导致集群之间交互频繁,重发数据在内存中不断堆积。
方案:JBoosCache官方讨论过内存溢出的问题并在后续版本中改进。MIS在同步最后操作时间,实现方案上的缺陷改进。
堆外内存导致的溢出错误
背景:学校的小型项目,基于B/S的电子考试系统,实现客户端能从服务端接受数据,逆向Ajax技术,Jetty7.1.4 普通PC机i5 CPU 4GB内存 32位Windows操作系统。
现状:服务器不定时抛出内存溢出异常
问题:内存溢出
原因:加上参数-XX:+HeapDumpOnOutOfMemoryError运行一段时间,没有任何反应,GC也并不频繁,Eden,Survivor,老年代都很稳定。内存溢出后,从系统日志找到堆栈。
操作系统对每个进程管理的内存时有限制的,32位的系统,最大使用的内存时2GB,JVM使用了1.6GB,剩下的只有0.4GB。虽然收集器也会堆Direct Memory区域进行回收,但是只是在Full GC后顺便回收。而且Direct Memory也不会通知收集器,直到异常。
本系统恰好有大量的NIO操作使用到Direct Memory内存
外部命令导致系统缓慢
背景:一个数字校园应用系统,大并发测试时发现请求响应比较慢。
问题:请求响应比较慢
原因:通过mpstat工具发现CPU使用率很高,并且绝大数资源消耗并不是系统本身。DTrace运行后发现消耗CPU最多的时fork系统调用,而fork时Linux用来产生新进程的,JVM只有线程,不应该有进程。
系统设计时每个用户请求都需要执行一个外部shell脚本,通过Java的Runtime.getRuntime().exec()方法调用,这种方法能达到目的,但是非常消耗资源。
Runtime.getRuntime().exec()是首先克隆一个和当前虚拟机拥有一样环境标量的进程,再用这个新的进程去执行外部命令,最后再退出这个进程。不仅CPU资源消耗大,内存负担也很重
服务器JVM进程崩溃
等待的线程和Socket连接数太多,超过虚拟机的承受能力,导致虚拟机崩溃。
不恰当的数据结构导致内存占用过大
背景:一台RPC的服务器,平时地外服务,GC在30毫秒左右,完全可以接受。
问题:业务上需要每10分钟加载一个约80MB的数据文件到内存中,会有超过100万个HashMap,键值对为Long,Long,这段时间GC时间会超过500ms.
原因:复制算法对在对付朝生夕灭的对象时很高效。但是在分析800MB数据期间,Eden空间很容易就满了,而对象还都存活,复制大量的对象到Survivor并且更新引用,导致GC暂停明显。
方案:从 GC优化的角度,将Survivor空间去掉。(-XX:SurvivorRatio-65535,-XX:MaxTenuringThreshold=0或者-XX:AlawaysTenure);从程序设计的角度,只有HashMap存放的key和value有效,不需要使用装箱类。本来只有2*8Byte的,装箱之后多了8Byte的MarkWord,8Byte的Class指针,再加上8Byte的数据。组装成Entry,有多了16Byte的头,8Byte的next,4Byte的hash字段,4Byte的空白填充。空间利用率是16Byte/88Byte=18%,实在太低了。
由Windows虚拟内存导致的长时间停顿
问题:Java的GUI程序在程序最小化时,它的工作内存被自动交换到磁盘的页面文件中了,这样GC时就因为恢复页面文件的操作而导致不正常GC停顿
方案:Java的GUI程序要避免这种情况发生,可以加入参数“-Dsun.awt.keepWorkingSetOnMinimize=true”,这个参数很多桌面程序都会用到,如VisualVM,用来保证程序在恢复最小化时能够立即响应。
Eclipse调优
JVM调优不仅限于服务端应用,也可以自己调优测试,如Eclipse应用。
运行平台32位Windows系统,i5 CPU,4GB内存。
初始配置文件在eclipse.ini中,作者改了JDK路径,设置最大堆512MB,开启了JMX管理,其它未做改动。
由于安装了很多插件,启动较慢。
eclipse代码规模较大,增加永久代内存,默认时64MB
-Dcom.sun.management.jmxremote
-Dosgi.requiredJavaVersion=1.5
-Xmx512MB
-XX:MaxPermSize=256MB
去掉类加载时的字节码验证,如果觉得eclipse编译是的字节码是可靠的话
-Xverify:none
通过VisualVM发现启动eclipse时,频繁GC,由于新生代内存分配不足导致的
新增的配置如下:
-Xverify:none
-Xmx512m
-Xms512m
-Xmn128m
-XX:PermSize=96m
-XX:MaxPermSize=96m
最后还可以按照之前的文章,为eclipse配置垃圾收集器,为了减少响应时间,可以选择CMS收集器,当然优化的时候可以配合VisualVM工具,来观察优化的结构,进而调整优化参数
最终新增的配置如下:
-Xverify:none
-Xmx512m
-Xms512m
-Xmn128m
-XX:PermSize=96m
-XX:MaxPermSize=96m
-XX:+DisableExplicitGC
-Xnoclassgc
-XX:+UseParNewGC
-XX:+UseConcMarkSweepGC
-XX:CMSInitiatingOccupancyFraction=85
- 深入理解JVM(五)——JVM调优 Eclipse调优
- 深入理解JVM—JVM内存模型
- 深入理解JVM—JVM内存模型
- 深入理解JVM—JVM内存模型
- 深入理解JVM—JVM内存模型
- 深入理解JVM—JVM内存模型
- 深入理解JVM—JVM内存模型
- 深入理解JVM—JVM内存模型
- 深入理解JVM—JVM内存模型
- 深入理解JVM—JVM内存模型
- 深入理解JVM—JVM内存模型
- 深入理解JVM—JVM内存模型
- 深入理解JVM—JVM内存模型
- 深入理解JVM—JVM内存模型
- 深入理解JVM—JVM内存模型
- 深入理解JVM—JVM内存模型
- 深入理解JVM—JVM内存模型
- 深入理解JVM—JVM内存模型
- Thinkphp5学习(26)调试和日志
- JustOj1227: 统计单词个数
- jQuery初始化
- python中的单例模式
- SpringBoot非官方教程 | 第十二篇:springboot集成apidoc
- 深入理解JVM(五)——JVM调优 Eclipse调优
- Atcoder ARC 077 E
- 杨辉三角的多解(转载)
- Android自定义控件时的事件处理方法
- ida android incompatible debugger server protocol version is 17,expected 19
- Java之字符流、字符缓冲流
- 1121: [POI2008]激光发射器SZK
- Opencv3.2+opencv_contrib+VS2015配置问题汇总
- 详细比较三个 CSS 预处理器(框架):Sass、LESS 和 Stylus