本文是Effective Java专栏Java虚拟机专题的第十讲,如果你觉得看完之后对你有所帮助,欢迎订阅本专栏,也欢迎您将本专栏分享给你身边的工程师同学。
前言
在这之前,我写过一篇文章 —— 关于Java虚拟机性能调优的清单,文章里我梳理了JVM调优的所需理论知识和常用工具清单,今天就让我们使用这份清单,进行一次JVM的调优实战!
我为什么选择Eclipse来调优
虽然IntelliJ IDEA的风头似乎已经盖过了Eclipse,但由于工作的原因,在大多数时候我还是使用Eclipse作为开发工具,我想现在使用Eclipse的程序员也一定很多。
那么,正在使用或者曾经使用过Eclipse的你,有没有想过:
- Eclipse是采用什么垃圾收集器?
- 启动的时候,都执行了多少次GC?
- 能不能对Eclipse的启动速度进行调优?
这篇文章,介绍一下我是如何对Eclipse进行调优,使得它的启动速度提升了1.5秒的。
你可能会说,才1.5秒,需要说的是,笔者的电脑性能比较牛,优化前启动Eclipse只需要5953ms,优化结束后是4693ms,提升了21%的速度,这就像百米赛跑,第一名的博尔特和最后一名的差了不到1秒钟,但已经完全是不同的境界了!
下面让我们开始提速吧!
环境信息
- Eclipse: eclipse-standard-kepler-R-win32-x86_64,需要配套1.6+的JDK
- JDK:jdk1.7.0_51
- 机器环境:WIN10, 64位,12G内存,i7处理器
调优前的启动速度
为了方便计算Eclipse的启动速度,这里使用了周志明老师写的一个Eclipse插件,该插件可以在Eclipse启动完成后,计算当前时间和Eclipse开始启动时间直接的间隔,然后在界面上打印出总的启动时间,就像这样:
插件下载地址:华章图书 - 深入理解Java虚拟机:JVM高级特性与最佳实践(第2版)
下载里面的教辅源代码,插件在第五章的源代码中。
笔者一开始的eclipse.ini配置是这样的:
-vm
C:/Program Files/Java/jdk1.7.0_51/bin/javaw.exe
-startup
plugins/org.eclipse.equinox.launcher_1.3.0.v20130327-1440.jar
--launcher.library
plugins/org.eclipse.equinox.launcher.win32.win32.x86_64_1.1.200.v20130521-0416
-product
org.eclipse.epp.package.standard.product
--launcher.defaultAction
openFile
--launcher.XXMaxPermSize
128M
-showsplash
org.eclipse.platform
--launcher.XXMaxPermSize
128M
--launcher.defaultAction
openFile
--launcher.appendVmargs
-vmargs
-Dosgi.requiredJavaVersion=1.6
-Xms40m
-Xmx128M
配置里面主要是指定了使用JDK7,初始堆大小(-Xms)是40m,最大堆(-Xmx)是128m.
接着,笔者启动了三次Eclipse,三次的启动时间分别是5960ms、5945ms、5954ms,取平均值之后,调优前的启动时间是5953ms.
同时笔者通过使用Visual VM,记录了调优前虚拟机的运行状况:
从Visual VM的监控信息看,启动时间主要有三大块:编译时间、类加载时间以及垃圾回收的停顿时间。
其中,编译时间是指JVM的JIT编译,笔者是64位的机器,只能采用server模式,因此在即时编译上没有什么优化的余地。
关于JIT编译器、server模式和client模式,可以参考 解释执行和即时编译器
因此,下面主要对耗时3.468秒的类加载时间,以及新生代(Eden Space)总耗时107ms的13次GC和老年代(Old Gen)总耗时156ms的Full GC,进行调优。
类加载时间调优
JVM的类加载,是指将Class文件,加载到虚拟机中。类加载的过程,包括加载、验证、准备、解析、使用、卸载等阶段。
其中验证,是由于Class文件不全都是由Java源码编译而来,Class文件可以使用任何途径产生,甚至可以直接使用十六进制编辑器来编写。因此虚拟机要对Class文件进行验证。而对于Eclipse来说,虚拟机要加载的文件,基本都是我们自己编写的源码,是值得信任的,因此,可以加入参数-Xverify:none将类加载时的验证阶段去掉。
去掉之后,再来看Visual VM里的类加载时间,可以看到类加载时间一下子下降到2s:
同样的,再来启动三次Eclipse,时间分别是4687ms、4700ms、4695ms,取平均值,去掉验证阶段后的Eclipse的启动时间为4694ms。
垃圾收集的时间调优
再来对垃圾收集进行调优,首先,我们打印一下GC日志,来看看现在Eclipse采用的是什么垃圾收集器,在eclipse.ini中加入:
-XX:+PrintGCTimeStamps
-XX:+PrintGCDetails
-Xloggc:gc.log
启动后查看gc.log:
0.373: [GC [PSYoungGen: 10752K->1528K(12288K)] 10752K->2853K(39936K), 0.0087200 secs] [Times: user=0.05 sys=0.01, real=0.01 secs]
0.641: [GC [PSYoungGen: 12280K->1512K(23040K)] 13605K->5449K(50688K), 0.0053889 secs] [Times: user=0.00 sys=0.00, real=0.01 secs]
1.205: [GC [PSYoungGen: 23016K->1522K(23040K)] 26953K->13258K(50688K), 0.0089067 secs] [Times: user=0.00 sys=0.00, real=0.01 secs]
1.667: [GC [PSYoungGen: 23026K->1515K(42496K)] 34762K->16585K(70144K), 0.0061016 secs] [Times: user=0.00 sys=0.02, real=0.01 secs]
1.809: [GC [PSYoungGen: 42475K->1515K(42496K)] 57545K->16937K(70144K), 0.0049001 secs] [Times: user=0.02 sys=0.00, real=0.01 secs]
2.372: [GC [PSYoungGen: 42475K->1528K(23040K)] 57897K->24396K(50688K), 0.0109632 secs] [Times: user=0.05 sys=0.02, real=0.01 secs]
2.383: [Full GC [PSYoungGen: 1528K->0K(23040K)] [ParOldGen: 22868K->22517K(51200K)] 24396K->22517K(74240K) [PSPermGen: 23460K->23448K(47104K)], 0.1348976 secs] [Times: user=0.38 sys=0.00, real=0.13 secs]
2.970: [GC [PSYoungGen: 21504K->8905