当前位置: 首页 > 科技观察

JVM性能调优实战:让你的IntelliJIdea如丝般顺滑

时间:2023-03-12 21:20:19 科技观察

前言上一篇整理了一篇关于JVM故障诊断与处理工具的文章。考虑到大部分Java程序员都使用IntelliJIdea,本文只是使用工具实战实战??,调优IntelliJIdea的运行速度。调优前的运行状态。原始配置内容查询idea原始配置文件路径,可以在VisualVM中的overview中查看原始配置内容:-XX:ReservedCodeCacheSize=240m-XX:+UseCompressedOops-Dfile.encoding=UTF-8-XX:SoftRefLRUPolicyMSPerMB=50-ea-Dsun.io.useCanonCaches=false-Djava.net.preferIPv4Stack=true-Djdk.http.auth.tunneling.disabledSchemes=""-XX:+HeapDumpOnOutOfMemoryError-XX:-OmitStackTraceInFastThrow-XX:ErrorFile=$USER_HOME/java_error_in_idea_%p.log-XX:HeapDumpPath=$USER_HOME/java_error_in_idea.hprof-Xmx512m打印启动时间插件开发需要直观的看到优化前和优化后启动时间的变化,所以需要简单开发一个创意插件。Idea插件开发的过程可以参考我之前的文章《IDEA插件:多线程文件下载插件开发 》JVM启动时间到所有组件初始化完成后的时间,也就是IDEA的启动时间。代码如下es.showMessageDialog("Milliseconds:"+costTime,"Startuptime",Messages.getInformationIcon());}}在plugin.xml中添加如下代码:="cn.silently9527.MyApplicationInitializedListener"/>启动信息及优化前耗时根据VisualGC和IDEA启动插件收集的信息:IDEA启动耗时15s,共22次垃圾回收,耗时1.2s,其中新生代有17次GC,耗时324ms;老年代5次GC,加载27526个类耗时953ms,耗时21s?根据这个数据,算正常,15s其实是可以接受的范围,因为本文主要演示性能调优,所以需要测试能不能更快?开始尝试优化调整内存来控制垃圾回收的频率。从图中可以看出,启动参数指定的512m内存中,只有169m分配给了newgeneration,因为IDEA是我们开发常用的工具,平时的编译过程也需要足够的内存,所以需要扩容首先是总内存,这里我设置了最大内存-Xmx1024m,这样JVM在GC的时候就不用浪费时间动态计算扩容大小了,同时也设置了-Xms1024m;在启动过程中,Eden总共有17次GC。为了减少新生代的GC次数,我将新生代的内存大小设置为-Xmn256m;重启后查看VisualGC,新生代GC次数从17次减少到7次,耗时从324ms减少到152ms内存调整前有5次FullGC,内存调整后还有4次FullGC,但是从两张图我们可以看出老年代还有很多剩余空间,应该不会发生FullGC;考虑代码中是否有手动调用System.gc()触发FullGC的地方,于是加上参数-XX:+DisableExplicitGC,再次重启IDEA,结果很失望,还是有4次FullGC;再次仔细观察优化在上图中,注意LastCause:MetadataGCThreshold,最后一次GC是本应因Metaspace区域内存不足而发生的GC。为了验证我们的猜测,把GC日志打印出来看看。在idea.vmoptions中添加打印日志相关的参数:-XX:+PrintGCDetails-XX:+PrintGCDateStamps-Xloggc:../gc.log?JVMGC日志的主要参数包括:-XX:+PrintGC输出GC日志-XX:+PrintGCDetails输出GC详细日志-XX:+PrintGCTimeStamps输出GC时间戳(基准时间形式)-XX:+PrintGCDateStamps输出GC时间戳(日期形式,如2013-05-04T21:53:59.234+0800)-XX:+PrintHeapAtGC打印出GC前后的heap信息-Xloggc:../logs/gc.log日志文件输出路径?重启idea,查看gc.log?其中PSYoungGen:表示ParallelScavenge垃圾新生代使用的收集器,31416K->0K(181248K)表示gc前使用的内存大小->gc后使用的内存大小(该区域的总内存大小)?我们从日志中可以看出每次FullGC都是由于MetadataGCThreshold,Metaspace每次GC回收的内存几乎没有,只是扩大了这块区域的容量;如果找到原因就好办了,添加如下参数调整Metaspace的大小:-XX:MetaspaceSize=256m再次重启Idea后,发现FullGC没有了。我心情很好。打开一个大项目,点击编译代码进行测试,发现思路卡住了。检查VisualGC后发现堆内存还是空闲的,只有Metaspace被充分利用了。已经满了,所以我给的最大空间设置太小了,直接去掉-XX:MaxMetaspaceSize=256m选择垃圾收集器从刚才的gc日志可以发现默认是用ParallelScavenge+Parallel旧的垃圾收集器,这个组合侧重于吞吐量。这里我们尝试换成低延迟的垃圾收集器,尝试ParNew+CMS。在idea.vmoptions中添加如下配置:-XX:+UseConcMarkSweepGC-XX:+UseParNewGC重启IDEA后查看VisualGC很尴尬,也发生了6次gc,ParallelScavenge+ParallelOld组合用了197ms,ParNew+CMS组合用了379ms;虽然是这样的结果,但是我们需要考虑到目前只发生了MinorGC,如果发生了FullGC,结果会怎样呢?你可以自己测试G1。让我们试试另一个新的G1垃圾收集器。在idea.vmoptions中添加如下配置:-XX:+UseG1GC这个结果好像有点慢。我已经多次测试过这两个垃圾收集器。虽然每次的结果都不一样,但是相差不远,所以垃圾收集器可以自己选择。这里我们选择G1类加载时间优化。根据前面的分析,idea开始加载classes27526,耗时21s,能不能优化一下?因为idea是一个常用的开发工具,经常被很多人使用,我们可以认为它的代码是安全的,是否符合当前虚拟机的要求,不会危及虚拟机的安全,所以我们使用参数-Xverify:none禁用字节码校验过程,耗时11s,重启IDEA,效果还是比较明显的。全部优化完成后,经过多次重启测试,平均启动时间下降到11s。安慰一下,这次手术没有白费。做一张11s以下的图