前言
最近在读周志明大大的《深入理解Java 虚拟机》,看到大大对ecplise进行调优,手痒痒,想着亲手给自己的IDEA也做一次调优,正好最近电脑升级了一次内存,之前的配置肯定也不适合了,废话不多说,直接开搞!
环境介绍
IDEA:2019.1.3 64位(安装在固态盘)
JDK:1.8 64位
内存大小:16GB
使用软件:Java VisualVM,jstat ,jps
不要直接复制最后的配置,每台机器和环境都不一样,直接复制不能起到调优的效果,反而有可能起到反作用!!!!
启动时间计算标准:测试使用同一个SSM的Web项目,启动时间从双击到IDEA验证完项目中的Spring 配置为止
因为IDEA安装插件会影响启动速度,列举一下已安装的插件
优化前
IDEA初始配置
-Xms128m
-Xmx750m
-XX:ReservedCodeCacheSize=240m
-XX:+UseConcMarkSweepGC
-XX:SoftRefLRUPolicyMSPerMB=50
-ea
-Dsun.io.useCanonCaches=false
-Djava.net.preferIPv4Stack=true
-Djdk.http.auth.tunneling.disabledSchemes=""
-XX:+HeapDumpOnOutOfMemoryError
-XX:-OmitStackTraceInFastThrow
统计:
- 启动时间:62s
- Minor GC:75次 耗时1.006s
- Full GC:12次 耗时0.535s
分析
首先Minor GC,和Full GC次数有点太多了,Minor GC次数多的原因主要就是Eden区过小,反正内存16GB肯定够用了,干脆就给他分配2GB看看效果,至于Full GC,引发的原因有很多种,稍后再分析讨论
第一次优化
-Xms2048m
-Xmx2048m
-Xmn768m
-XX:ReservedCodeCacheSize=240m
-XX:+UseConcMarkSweepGC
-XX:SoftRefLRUPolicyMSPerMB=50
-ea
-Dsun.io.useCanonCaches=false
-Djava.net.preferIPv4Stack=true
-Djdk.http.auth.tunneling.disabledSchemes=""
-XX:+HeapDumpOnOutOfMemoryError
-XX:-OmitStackTraceInFastThrow
这次优化配置将初始堆大小变为2GB,最大堆大小也变为2GB,新生代的堆大小初始为768MB
统计
-
启动时间:42.25s
-
Minor GC:5次 耗时0.48s
-
Full GC:6次 耗时0.42s
分析
Minor GC的次数已经算是很正常了,但是Full GC的次数好像还是有点多,但是从图中可以看出,Old区并没有存储多少东西,这里使用jstat查看一下发生GC的原因
可以看到引发Full GC 的原因是由于元空间不足发生了扩容引起的,那么下一步优化的思路应该就从元空间入手了
第二次优化
-Xms2048m
-Xmx2048m
-Xmn768m
-XX:ReservedCodeCacheSize=240m
-XX:+UseConcMarkSweepGC
-XX:SoftRefLRUPolicyMSPerMB=50
-ea
-Dsun.io.useCanonCaches=false
-Djava.net.preferIPv4Stack=true
-Djdk.http.auth.tunneling.disabledSchemes=""
-XX:+HeapDumpOnOutOfMemoryError
-XX:-OmitStackTraceInFastThrow
-XX:MetaspaceSize=512m
这次使用-XX:MetaspaceSize参数,将元空间的初始大小改大一些
统计
-
启动时间:39s
-
Minor GC:4次 耗时0.4s
-
Full GC:1次 耗时0.8s
分析
这次Full GC 只发生了一次,为什么还发生一次,元空间的大小应该是足够了呀!!!本着一次都不能忍的原则,再次使用jstat查看一次引发GC的原因
发现目标,是IDEA启动时代码中使用 System.gc() 触发了这一次的Full GC,我们空间是完全足够的,所以这次Full GC是完全没必要的。干掉它
第三次优化
-Xms2048m
-Xmx2048m
-Xmn768m
-XX:ReservedCodeCacheSize=240m
-XX:+UseConcMarkSweepGC
-XX:SoftRefLRUPolicyMSPerMB=50
-ea
-Dsun.io.useCanonCaches=false
-Djava.net.preferIPv4Stack=true
-Djdk.http.auth.tunneling.disabledSchemes=""
-XX:+HeapDumpOnOutOfMemoryError
-XX:-OmitStackTraceInFastThrow
-XX:MetaspaceSize=512m
-XX:+DisableExplicitGC
这里使用-XX:+DisableExplicitGC参数,将代码中的System.gc()触发的GC给禁用掉,再次看看效果
统计
-
启动时间:38s
-
Minor GC:5次 耗时0.5s
-
Full GC:0次 耗时 0s
分析
虽然只是优化了1s,但是没有发生Full GC 就很舒服了,好像垃圾收集方面没啥可以搞得了,将目标转向上面的类加载时间,这玩意长,搞他肯定合理,先看一下搞之前的类加载时间
第四次优化
-Xms2048m
-Xmx2048m
-Xmn768m
-XX:ReservedCodeCacheSize=240m
-XX:+UseConcMarkSweepGC
-XX:SoftRefLRUPolicyMSPerMB=50
-ea
-Dsun.io.useCanonCaches=false
-Djava.net.preferIPv4Stack=true
-Djdk.http.auth.tunneling.disabledSchemes=""
-XX:+HeapDumpOnOutOfMemoryError
-XX:-OmitStackTraceInFastThrow
-XX:MetaspaceSize=512m
-XX:+DisableExplicitGC
-Xverify:none
这个优化吧,诚实的讲完全是周大大书上说的,我自己是想不到的,他说是JDK6之后添加的类型检查验证器会影响到以前的类型检查验证器的工作,他调优的是Ecplise,说由于使用人数多,编译代码可以认为肯定是安全可靠的,因此没必要进行字节码验证。狗头一下,那我就说IDEA使用人数甚多,也是很没必要的,咱也禁用(禁用参数 -Xverify:none)
统计
-
启动时间:35s
-
Minor GC:5次 耗时0.5s
-
Full GC:0次 耗时 0s
分析
事实证明,禁用掉确实很合理,类加载时间从58s优化到46s,到此好像也没啥优化的了,于是我有去网上找了一下可以优化的点,由于没给我带来啥明显的提升,所以就放到一起写了
倒数第一次优化
-Xms2048m
-Xmx2048m
-Xmn768m
-XX:ReservedCodeCacheSize=240m
-XX:+UseConcMarkSweepGC
-XX:SoftRefLRUPolicyMSPerMB=50
-ea
-Dsun.io.useCanonCaches=false
-Djava.net.preferIPv4Stack=true
-Djdk.http.auth.tunneling.disabledSchemes=""
-XX:+HeapDumpOnOutOfMemoryError
-XX:-OmitStackTraceInFastThrow
-XX:MetaspaceSize=512m
-XX:+DisableExplicitGC
-Xverify:none
-XX:+UseNUMA
-Xnoclassgc
-XX:CMSInitiatingOccupancyFraction=75
-XX:CMSFullGCsBeforeCompaction=3
-Xnoclassgc:禁用掉JVM的类的垃圾回收
-XX:+UseNUMA:这个说起来比较复杂,有兴趣参考链接
-XX:CMSInitiatingOccupancyFraction=75:当老年代容量使用到75%时就触发Full GC,默认是92%,因为这里我们使用的是ParNew + CMS的垃圾收集器组合,到达92%再进行清理容易引起CMS由于没有足够的空余位置协助清理造成并发失败,然后会冻结用户的线程(IDEA长时间卡顿的原因),去使用古老的Serial Old收集器(单线程的哦)进行收集。
-XX:CMSFullGCsBeforeCompaction=3:CMS 是基于标记清除的算法,意味着会产生很多空间碎片,这个参数就是指定发生多少次Full GC对空间做一次压缩整理,默认是0,即每次都整理,有点浪费时间
统计
-
启动时间:34s
-
Minor GC:4次 耗时0.38s
-
Full GC:0次 耗时 0s
分析
通过启动速度可以看出,上面设置的参数对于启动速度的优化没有多大的提升,这是很正常的,他们的价值还将会体现在IDEA长时间使用的时候。
Q&A
为什么不使用G1收集器?
其实我背地里悄悄的用了,上面最后一次配置,我将CMS换为G1后,时间又长了。。。我的理解应该是G1复杂的记忆集和对写屏障的复杂操作,使得G1消耗更多的计算资源和内存资源,在2GB的内存大小下,与CMS相比并不占优势,在更大的内存下G1的优势才能彻底发挥出来,所以我从一开始就没考虑过G1,一直是针对CMS进行的优化,上面的优化参数也仅仅是针对我电脑下CMS垃圾收集器优化的,如果你想使用G1,按照参考这个思路,针对G1去做一次优化。(纯属个人见解,错误之处请指正)
Java VisualVM、jstat、jps在哪?
jstat、jps 安装完jdk并配置好环境变量后就可以在终端中直接使用,命令形式如上面截图。
Java VisualVM 在jdk根目录的bin文件夹下,如果没有,说明你的jdk版本比较新(起码jdk8后面的了),需要单独去下载
我的 Java VisualVM 连接上后为什么没有你那么多功能?
我的是安装完所有的插件,安装位置工具--插件--可用插件,安装比较慢的(你懂得,科学一下)
还有优化点吗?
有,肯定有。首先肯定是电脑性能问题,这个需要靠钱解决。其次,固态盘比较大的可以考虑放在固态盘中,提升很明显。还有每次JDK、IDEA新版本的发布都会不仅仅是发布新功能,肯定也会有性能的提升,可以考虑换一下新的版本。至于参数的优化方面,肯定是也还有,这能说我这参数达到的我优化的目的,肯定不是最好的,剩下的调优交给时间吧!
这些IDEA的配置要写在那个配置文件中?
我是直接在IDEA中修改的,位置如下:
我在IDEA中改完配置后启动不了了怎么办?
首先,在修改的时候最好是一个参数一个参数的修改或者添加,如果发生参数拼写出错,设置不合理,格式不对,或者参数冲突都会造成IDEA无法启动,这时候你可以去下面两个位置找一下IDEA的配置文件,将最后一次的参数改掉就可以启动了
位置1:IDEA的安装目录bin文件夹下(32位的找上面配置文件,64位的找下面的配置文件)
如果发现这两个配置文件中的配置信息都不是你最近改的配置,说明你的IDEA使用的配置文件并不是这里的
请找位置2:C盘--用户(Users)--你的用户名--idea用户配置文件夹--config目录