JVM性能调优实战:让你的IntelliJ Idea纵享丝滑

本文已被Github仓库收录 https://github.com/silently9527/JavaCore

前言

在前面整理了一篇关于JVM故障诊断和处理工具,考虑到大部分的Java程序员都使用的时IntelliJ Idea,本篇就使用工具来实战演练对IntelliJ Idea运行速度调优

调优前的运行状态

原始配置内容

要查询idea原始配置文件的路径可以在VisualVM中的概述中查看

image

原始配置内容:

-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插件开发的流程建议参考我以前的文章《IDEA插件:多线程文件下载插件开发

JVM的启动时间到所有组件初始化完成后的时间就看做是IDEA的启动时间,代码如下

public class MyApplicationInitializedListener implements ApplicationInitializedListener {
    @Override
    public void componentsInitialized() {
        RuntimeMXBean bean = ManagementFactory.getRuntimeMXBean();
        long startTime = bean.getStartTime();
        long costTime = System.currentTimeMillis() - startTime;

        Messages.showMessageDialog("毫秒:" + costTime, "启动耗时", Messages.getInformationIcon());
    }
}

plugin.xml中添加如下代码:

<extensions defaultextensionns="com.intellij">
    <applicationinitializedlistener id="MyApplicationInitializedListener" implementation="cn.silently9527.MyApplicationInitializedListener" />
</extensions>

优化前的启动信息与时间消耗

image
image

根据VisualGC和IDEA启动插件收集到的信息:

  • IDEA启动耗时 15s
  • 总共垃圾收集22次,耗时1.2s,其中新生代GC 17次,耗时324ms; 老年代GC 5次,耗时953ms
  • 加载类27526个,耗时 21s

> 按照这个数据来看也算是正常,15s 其实也在接受范围内,由于本文主要演示性能调优,所以需要测试能否在快一些

开始尝试优化

调整内存来控制垃圾回收频率

图上我们可以看出,启动参数指定的512m的内存被分配到新生代的只有169m,由于IDEA是我们开发常用的工具,平时的编译过程也需要足够的内存,所以我们需要先把总的内存扩大,这里我设置最大的内存-Xmx1024m,为了让JVM在GC期间不需要再浪费时间再动态计算扩容大小,同时也设置了-Xms1024m

在启动的过程中Eden共发生了17次GC,为了减少新生代gc次数,我把新生代的内存大小设置成-Xmn256m;

重新启动之后查看VisualGC,新生代gc次数从 17次 降低到了 7次,耗时从 324ms 降低到了 152ms。

image

在调整内存前发生了5次Full GC,调整内存后的依然还是有4次Full GC,但是从两张图我们可以看出,老年代的空间还有很多剩余,是不应该发生Full GC的;考虑是否是代码中有地方手动调用System.gc()出发了Full GC,所以添加了参数-XX:+DisableExplicitGC,再次重新启动IDEA,结果很失望,依然还有4次Full GC;

再次仔细观察优化前的图,注意看 Last Cause: Metadata GC Threshold , 最后一次gc是应该Metaspace区域内存不够发生的GC,为了验证我们的猜想,打印出GC日志来看看。在idea.vmoptions中添加打印日志相关的参数:

-XX:+PrintGCDetails
-XX:+PrintGCDateStamps
-Xloggc:../gc.log

JVM的GC日志的主要参数包括如下几个:

  • -XX:+PrintGC 输出GC日志
  • -XX:+PrintGCDetails 输出GC的详细日志
  • -XX:+PrintGCTimeStamps 输出GC的时间戳(以基准时间的形式)
  • -XX:+PrintGCDateStamps 输出GC的时间戳(以日期的形式,如 2013-05-04T21:53:59.234+0800)
  • -XX:+PrintHeapAtGC 在进行GC的前后打印出堆的信息
  • -Xloggc:../logs/gc.log 日志文件的输出路径

重新启动idea,查看gc.log

image

> 其中PSYoungGen:表示新生代使用的ParallelScavenge垃圾收集器,31416K-&gt;0K(181248K)表示 gc前已使用的内存大小 -> gc后已使用内存大小(该区域的总内存大小)

从日志中我们看出每次Full GC都是因为Metadata GC Threshold,而Metaspace每次gc回收的内存几乎没有,仅仅是扩大了该区域的容量;找到了原因那就好办了,添加如下的参数调整Metaspace的大小:

-XX:MetaspaceSize=256m

再次重启Idea之后,发现Full GC没有了,心情很爽

image

测试打开大项目点击编译代码,发现自己的idea卡死了,查看VisualGC之后发现堆内存都还有空闲,只有Metaspace被全部占满了,所以是自己给的最大空间设置太小,所以直接去掉了-XX:MaxMetaspaceSize=256m

选择垃圾收集器

从刚才的gc日志中,我们可以发现默认使用的是ParallelScavenge + Parallel Old垃圾收集器,这个组合注重的是吞吐量,这里我们尝试换一个注重低延时的垃圾收集器试一试

  • ParNew + CMS
    idea.vmoptions中添加如下配置:
-XX:+UseConcMarkSweepGC
-XX:+UseParNewGC

重启IDEA之后查看VisualGC

image

很尴尬,同样发生了6次gc,ParallelScavenge + Parallel Old的组合耗时197ms,而ParNew + CMS的组合耗时379ms;虽然是这个结果,但是我们需要考虑当前只发生了MinorGC,如果发生FullGC了结果又会如何了,大家可以自己测试一下

  • G1
    我们在换一个最新的G1垃圾回收器试试,在idea.vmoptions中添加如下配置:
-XX:+UseG1GC
image

这个结果好像也还是要慢一点点,自己多次测试过这两个垃圾回收器,虽然每次结果都不一样,相差不远,所以垃圾回收器可以自己选择,这里我们选择的是G1

类加载时间优化

根据之前的分析,idea启动加载类27526个,耗时 21s,这个我们有办法能优化一下吗?因为idea是常用的开发工具,经常很多人的使用,我们可以认为它的代码是安全的,是否符合当前虚拟机的要求,不会危害虚拟机的安全,所以我们使用参数-Xverify:none来禁用字节码的验证过程

重启IDEA

image

耗时下降到了11s,效果还是比较明显的

总结

做完了所有优化之后,经过多次重启测试,平均的启动时间下降到了11s,为了安慰我本次操作没有白辛苦,搞一张11s以下的图

image

写到最后(点关注,不迷路)

文中或许会存在或多或少的不足、错误之处,有建议或者意见也非常欢迎大家在评论交流。

最后,白嫖不好,创作不易,希望朋友们可以点赞评论关注三连,因为这些就是我分享的全部动力来源🙏

image

原创不易 转载请注明出处:https://silently9527.cn/archives/102


我已经从零开始手写了简易版springmvc,以及编写了详细的说明文档,希望能够帮助伙伴们深入理解springmvc核心原理,有需要的朋友欢迎给我留言

image

image
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,470评论 6 501
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,393评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,577评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,176评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,189评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,155评论 1 299
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,041评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,903评论 0 274
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,319评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,539评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,703评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,417评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,013评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,664评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,818评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,711评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,601评论 2 353

推荐阅读更多精彩内容